-
Notifications
You must be signed in to change notification settings - Fork 54
@W-11261233@ Handle static blocks in classes #740
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
Conversation
| System.err.println(formatError(ex)); | ||
| return INTERNAL_ERROR; | ||
| } catch (UnexpectedException ex) { | ||
| LOGGER.error("Unexpected exception while loading graph", ex); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
New catch-all for Unexpected exceptions so that the error message is less cryptic.
| g.addE(Schema.PARENT).from(vChild).to(vNode).iterate(); | ||
| g.addE(Schema.CHILD).from(vNode).to(vChild).iterate(); | ||
|
|
||
| // Handle static block if needed |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If a block statement is found in the default <clint>() method, we know it's a static block. This redirection leads to the creation of a new synthetic static block method.
| if (node.getLabel().equals(ASTConstants.NodeType.METHOD)) { | ||
| MethodPathBuilderVisitor.apply(g, vNode); | ||
| } else if (ROOT_VERTICES.contains(node.getLabel())) { | ||
| StaticBlockUtil.createSyntheticStaticBlockInvocation(g, vNode); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we are at the end of handling a root (class/interface/trigger etc) node, check if any synthetic static block methods were created earlier. If yes, add a synthetic static block invoker method to invoke the static block methods.
| } | ||
|
|
||
| /** Add a property to the traversal, throwing an exception if any keys are duplicated. */ | ||
| protected void addProperty( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Extracted to GremlinVertexUtil for reuse.
| } else if (children.size() > 1) { | ||
| throw new UnexpectedException(children); | ||
| throw new UnexpectedException( | ||
| "Did not expect more than one child node of type " |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Adding more information to the exception.
| import org.apache.tinkerpop.gremlin.structure.Vertex; | ||
|
|
||
| /** Handles common operations performed while creating vertices on Graph */ | ||
| public final class GremlinVertexUtil { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Refactored existing code into this util for core reuse.
| * <p>private static void StaticBlockInvoker() { SyntheticStaticBlock_1(); SyntheticStaticBlock_2(); | ||
| * } } | ||
| */ | ||
| public final class StaticBlockUtil { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Most of the new logic is here.
| String definingType) { | ||
| // Create new synthetic method StaticBlockInvoker to invoke each synthetic static block | ||
| // method | ||
| final Vertex invokerMethodVertex = g.addV(ASTConstants.NodeType.METHOD).next(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Artificially creating a method and its structure to invoke each static block method.
| } | ||
| symbolProviderVisitor.popScope(classStaticScope); | ||
| classStaticScope.setState(AbstractClassScope.State.INITIALIZED); | ||
| alreadyInitializedStaticClasses.add(fullClassName); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Now tracking classes that were already initialized.
| List<BaseSFVertex> vertices = new ArrayList<>(); | ||
| vertices.addAll(classStaticScope.getFields()); | ||
| vertices.addAll(getFieldDeclarations(g, classStaticScope.userClass)); | ||
| vertices.addAll(getStaticBlocks(g, classStaticScope.userClass)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Adding calls to static blocks as another item needed to set a class's static scope.
| } | ||
| } | ||
|
|
||
| public static final class StaticBlockVertex extends MethodVertex |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Intermediary code that's not needed anymore. Will remove this.
| import java.util.List; | ||
| import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource; | ||
|
|
||
| public class GraphBuildTestUtil { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Extracting existing methods for reusability
| + "}"; | ||
|
|
||
| buildGraph(g, sourceCode); | ||
| GraphBuildTestUtil.buildGraph(g, sourceCode); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Changes from extracting methods to GraphBuiltTestUtil
| import org.junit.jupiter.api.BeforeEach; | ||
| import org.junit.jupiter.api.Test; | ||
|
|
||
| public class StaticBlockUtilTest { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
New tests to ascertain structure of synthetic methods.
| import org.junit.jupiter.api.Disabled; | ||
| import org.junit.jupiter.api.Test; | ||
|
|
||
| public class StaticCodeBlockInvocationTest { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Tests to verify static block invocation while setting static scope of class. I've added and disabled test cases that need future work.
|
|
||
| // Handle static block if needed | ||
| if (StaticBlockUtil.isStaticBlockStatement(node, child)) { | ||
| final Vertex parentVertexForChild = |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It looks like what's happening is that we detect that the child is a static block, and if so we create our synthetic method block to hold it, make that a child of the current parent, and make the block statement a child of that. Am I reading that right?
I'd love some commenting about what is being done here, and why it was necessary.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added more comments. Let me know if it explains sufficiently or I'll try expanding it some more.
| if (node.getLabel().equals(ASTConstants.NodeType.METHOD)) { | ||
| MethodPathBuilderVisitor.apply(g, vNode); | ||
| } else if (ROOT_VERTICES.contains(node.getLabel())) { | ||
| StaticBlockUtil.createSyntheticStaticBlockInvocation(g, vNode); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Again, I'd love a comment explaining what's going on here.
| * Creates a synthetic method vertex to represent a static code block | ||
| * | ||
| * @param g traversal graph | ||
| * @param clintVertex <clint>() method's vertex |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's clinit, not clint. It's a little thing, but it's in a bunch of places and it'll bug me if I don't mention it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the catch, I'll fix it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed everywhere
| * static blocks are represented like this: class StaticBlockClass { private static void <clint>() { | ||
| * { System.debug("inside static block 1"); } { System.debug("inside static block 2"); } } } | ||
| * | ||
| * <p>Having multiple block statements inside a method breaks SFGE's makes handling code blocks in |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This sentence seems like it's missing a bit?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like google formatter mauled the documentation. Let me try fixing this.
| * | ||
| * <p>private static void SyntheticStaticBlock_2() { System.debug("inside static block 2"); } | ||
| * | ||
| * <p>private static void StaticBlockInvoker() { SyntheticStaticBlock_1(); SyntheticStaticBlock_2(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does now get treated as if it had invoked StaticBlockInvoker?
As a general stop-gap for cryptic errors, this PR catches all UnexpectedExceptions at Main and displays a more friendly message to users while adding the actual stacktrace to logs.
Even though this PR leaves us in a better position than where we were (throwing illegible errors when static blocks were encountered), there are some open issues to handle in future: