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

rslint_parser panic #118

Open
rope-hmg opened this issue Sep 15, 2021 · 2 comments
Open

rslint_parser panic #118

rope-hmg opened this issue Sep 15, 2021 · 2 comments

Comments

@rope-hmg
Copy link

I tried this code:

// ⊕

I expected this to happen:
The parser should not crash

Instead this happened::

thread 'main' panicked at 'called `Option::unwrap()` on a `None` value', /Users/me/.cargo/git/checkouts/rslint-1a0b90046db1b20c/f7cc15b/crates/rslint_parser/src/lossless_tree_sink.rs:103:74
stack backtrace:
   0: rust_begin_unwind
             at /rustc/a178d0322ce20e33eac124758e837cbd80a6f633/library/std/src/panicking.rs:515:5
   1: core::panicking::panic_fmt
             at /rustc/a178d0322ce20e33eac124758e837cbd80a6f633/library/core/src/panicking.rs:92:14
   2: core::panicking::panic
             at /rustc/a178d0322ce20e33eac124758e837cbd80a6f633/library/core/src/panicking.rs:50:5
   3: core::option::Option<T>::unwrap
             at /rustc/a178d0322ce20e33eac124758e837cbd80a6f633/library/core/src/option.rs:388:21
   4: <rslint_parser::lossless_tree_sink::LosslessTreeSink as rslint_parser::TreeSink>::start_node::{{closure}}::{{closure}}
             at /Users/hector.maddock-gree/.cargo/git/checkouts/rslint-1a0b90046db1b20c/f7cc15b/crates/rslint_parser/src/lossless_tree_sink.rs:103:44
   5: core::option::Option<T>::unwrap_or_else
             at /rustc/a178d0322ce20e33eac124758e837cbd80a6f633/library/core/src/option.rs:429:21
   6: <rslint_parser::lossless_tree_sink::LosslessTreeSink as rslint_parser::TreeSink>::start_node::{{closure}}
             at /Users/hector.maddock-gree/.cargo/git/checkouts/rslint-1a0b90046db1b20c/f7cc15b/crates/rslint_parser/src/lossless_tree_sink.rs:101:21
   7: core::ops::function::impls::<impl core::ops::function::FnOnce<A> for &mut F>::call_once
             at /rustc/a178d0322ce20e33eac124758e837cbd80a6f633/library/core/src/ops/function.rs:280:13
   8: core::option::Option<T>::map
             at /rustc/a178d0322ce20e33eac124758e837cbd80a6f633/library/core/src/option.rs:489:29
   9: <core::iter::adapters::map::Map<I,F> as core::iter::traits::double_ended::DoubleEndedIterator>::next_back
             at /rustc/a178d0322ce20e33eac124758e837cbd80a6f633/library/core/src/iter/adapters/map.rs:142:9
  10: <core::iter::adapters::rev::Rev<I> as core::iter::traits::iterator::Iterator>::next
             at /rustc/a178d0322ce20e33eac124758e837cbd80a6f633/library/core/src/iter/adapters/rev.rs:33:9
  11: <core::iter::adapters::enumerate::Enumerate<I> as core::iter::traits::iterator::Iterator>::next
             at /rustc/a178d0322ce20e33eac124758e837cbd80a6f633/library/core/src/iter/adapters/enumerate.rs:44:17
  12: core::iter::adapters::peekable::Peekable<I>::peek::{{closure}}
             at /rustc/a178d0322ce20e33eac124758e837cbd80a6f633/library/core/src/iter/adapters/peekable.rs:239:43
  13: core::option::Option<T>::get_or_insert_with
             at /rustc/a178d0322ce20e33eac124758e837cbd80a6f633/library/core/src/option.rs:935:26
  14: core::iter::adapters::peekable::Peekable<I>::peek
             at /rustc/a178d0322ce20e33eac124758e837cbd80a6f633/library/core/src/iter/adapters/peekable.rs:239:9
  15: rslint_parser::lossless_tree_sink::n_attached_trivias
             at /Users/hector.maddock-gree/.cargo/git/checkouts/rslint-1a0b90046db1b20c/f7cc15b/crates/rslint_parser/src/lossless_tree_sink.rs:214:31
  16: <rslint_parser::lossless_tree_sink::LosslessTreeSink as rslint_parser::TreeSink>::start_node
             at /Users/hector.maddock-gree/.cargo/git/checkouts/rslint-1a0b90046db1b20c/f7cc15b/crates/rslint_parser/src/lossless_tree_sink.rs:106:13
  17: rslint_parser::event::process
             at /Users/hector.maddock-gree/.cargo/git/checkouts/rslint-1a0b90046db1b20c/f7cc15b/crates/rslint_parser/src/event.rs:103:21
  18: rslint_parser::parse::parse_with_syntax
             at /Users/hector.maddock-gree/.cargo/git/checkouts/rslint-1a0b90046db1b20c/f7cc15b/crates/rslint_parser/src/parse.rs:252:5
  19: code_style::main
             at ./crates/code-style/src/main.rs:62:42
  20: core::ops::function::FnOnce::call_once
             at /rustc/a178d0322ce20e33eac124758e837cbd80a6f633/library/core/src/ops/function.rs:227:5

Meta

rslint -V:

If building from source:
rustc --version --verbose:

rustc 1.56.0-nightly (371f3cd3f 2021-09-02)
binary: rustc
commit-hash: 371f3cd3fe523d0b398ed1db1620667c53ba7d02
commit-date: 2021-09-02
host: x86_64-apple-darwin
release: 1.56.0-nightly
LLVM version: 13.0.0

Additional context
I am using rslint_parser as a library in a tool I am writing and it failed to parse one of our files. After looking through the file for a while I noticed the above symbol in a comment. After removing it the parser succeeds.

I'm using a forked version of rslint, but I thought I'd raise an issue for this here anyway. I only created the fork a week or so ago anyway.

@Stupremee
Copy link
Member

Stupremee commented Sep 16, 2021

Which version are you using?
I just tried your text on my PC and it works fine with the latest master branch

Nvm, got it from your backtrace information.
Can you send the raw file because I can't reproduce it if I just copy your text.

@rope-hmg
Copy link
Author

This is the full text from the file.
There are three instances of that character and after removing them the parser no longer panics.

import Vector2D from 'core/engine/geometry/Vector2D';
import GraphPoint from 'core/plan/room-profile/editor/GraphPoint';
import { Wall } from 'core/plan/room-profile/editor/WallsHandler';
import { RoomProfileEvents } from 'core/plan/room-profile/RoomProfileEvents';
import { SelectedPoint } from 'core/plan/room-profile/editor/ui-modes/MovingMode/InteractableEntities/SelectedEntity';
import MovingMode from 'inject!core/plan/room-profile/editor/ui-modes/MovingMode/MovingMode';

describe('MovingMode', function () {
    beforeEach(function () {
        this.SelectedEntityFactory = jasmine.createSpyObj('SelectedEntityFactory', ['from']);
        this.HoveredEntityFactory = jasmine.createSpyObj('HoveredEntityFactory', ['from']);
        this.uiUtils = jasmine.createSpyObj('uiUtils', ['getWallUnderCursor', 'snapToWall']);

        this.SelectedEntityFactory.SelectedPoint = SelectedPoint;

        this.wallsHandler = jasmine.createSpyObj('wallsHandler', ['getAnchors', 'getWalls']);
        this.wallsHandler.getWalls.and.returnValue([]);

        this.events = jasmine.createSpyObj('events', ['emit']);
        this.auxiliaryPointsHandler = jasmine.createSpy('auxiliaryPointsHandler');

        const guideLinesHandler = jasmine.createSpyObj('guideLinesHandler', [
            'getClosestGuideLinesIntersection',
            'getClosestGuideLines',
            'updateClosestGuideLinesForWallPivots',
            'updateClosestGuideLines',
        ]);

        guideLinesHandler.getClosestGuideLines.and.callFake(() => []);

        const angleService = jasmine.createSpy('angleService');

        const roomShapeManipulator = jasmine.createSpyObj('roomShapeManipulator', ['moveAnchorBy']);

        const MovingModeConstructor = MovingMode({
            './InteractableEntities/HoveredEntity': this.HoveredEntityFactory,
            './InteractableEntities/SelectedEntity': this.SelectedEntityFactory,
            '../uiUtils': this.uiUtils,
            '../../../RoomProfileEvents': {
                events: this.events,
                RoomProfileEvents,
            },
        }).default;

        this.movingMode = new MovingModeConstructor(
            this.wallsHandler,
            angleService,
            this.auxiliaryPointsHandler,
            roomShapeManipulator,
            guideLinesHandler,
        );
    });

    describe('#handleMouseMove', function () {
        beforeEach(function () {
            this.event = jasmine.createSpyObj('event', ['preventDefault']);
        });

        describe('when dragging is in progress', function () {
            beforeEach(function () {
                spyOn(this.movingMode, 'isInProgress');
                this.movingMode.isInProgress.and.returnValue(true);
            });

            it('prevents default handling for event', function () {
                spyOn(this.movingMode, 'handleDrag');

                expect(this.event.preventDefault).not.toHaveBeenCalled();
                this.movingMode.handleMouseMove(Vector2D.zero, this.event);
                expect(this.event.preventDefault).toHaveBeenCalledOnce();
            });
        });
    });

    // o - cursor position
    // + - anchor position
    // ⊕ - cursor over anchor
    describe('dragging workflow', function () {
        beforeEach(function () {
            this.event = jasmine.createSpyObj('event', ['preventDefault']);
            this.interactableEntity = jasmine.createSpyObj('interactableEntity', [
                'getEntity',
                'getAffectedPoints',
                'getPosition',
                'move',
                'destroy',
            ]);

            this.HoveredEntityFactory.from.and.returnValue(this.interactableEntity);
            this.SelectedEntityFactory.from.and.returnValue(this.interactableEntity);
        });

        describe('for anchor', function () {
            beforeEach(function () {
                this.anchor = new GraphPoint(0, 0);

                this.interactableEntity.getEntity.and.returnValue(this.anchor);
                this.interactableEntity.getAffectedPoints.and.returnValue([this.anchor]);
                this.interactableEntity.getPosition.and.callFake(() => this.anchor.toVector2D());

                this.wallsHandler.getAnchors.and.returnValue([this.anchor]);

                // NOTE: cursorPosition is slightly shifted from the center of an anchor
                const startCursorPosition = this.anchor.toVector2D().add(new Vector2D(1, 1));

                this.movingMode.handleMouseMove(startCursorPosition);
                this.movingMode.handleMouseDown(startCursorPosition);
            });

            it('correctly calculates delta for dragged anchor when entity has not been restricted in previous movement step', function () {
                let desiredCursorPosition;

                // step 1
                desiredCursorPosition = new Vector2D(4, 0);
                this.movingMode.handleMouseMove(desiredCursorPosition, this.event);
                expect(this.interactableEntity.move).toHaveBeenCalledWith(
                    this.auxiliaryPointsHandler, new Vector2D(3, -1), undefined,
                );

                // emulate case when anchor is moved to desired position
                this.anchor.x = 3;
                this.anchor.z = -1;

                // step 2
                desiredCursorPosition = new Vector2D(0, 3);
                this.movingMode.handleMouseMove(desiredCursorPosition, this.event);
                expect(this.interactableEntity.move).toHaveBeenCalledWith(
                    this.auxiliaryPointsHandler, new Vector2D(-4, 3), undefined,
                );
            });

            //
            // ⊕  =1> +·o =2>
            //
            //                 ⊕
            it('correctly calculates delta for dragged anchor when anchor has been restricted in previous movement step', function () {
                let desiredCursorPosition;

                // step 1
                desiredCursorPosition = new Vector2D(4, 1);
                this.movingMode.handleMouseMove(desiredCursorPosition, this.event);
                expect(this.interactableEntity.move).toHaveBeenCalledWith(
                    this.auxiliaryPointsHandler, new Vector2D(3, 0), undefined,
                );

                // emulate case when anchor has been restricted from be moved to desired position
                this.anchor.x = 2; // desired is 3
                this.anchor.z = 0;

                // step 2
                desiredCursorPosition = new Vector2D(0, 3);
                this.movingMode.handleMouseMove(desiredCursorPosition, this.event);
                expect(this.interactableEntity.move).toHaveBeenCalledWith(
                    this.auxiliaryPointsHandler, new Vector2D(-3, 2), undefined,
                );
            });

            it('emits entityUnselected event on click on void canvas area', function () {
                const cursorPosition = new Vector2D(5, 5);
                this.movingMode.hoveredEntity = undefined;
                this.movingMode.handleMouseDown(cursorPosition, this.event);

                expect(this.events.emit).toHaveBeenCalledWith(RoomProfileEvents.entityUnselected);
            });
        });

        describe('for wall', function () {
            beforeEach(function () {
                this.wallStartPoint = new GraphPoint(1, 1);
                this.wallEndPoint = new GraphPoint(1, 3);
                this.wall = new Wall(this.wallStartPoint, this.wallEndPoint);

                this.interactableEntity.getEntity.and.returnValue(this.wall);
                this.interactableEntity.getAffectedPoints.and.returnValue([this.wallStartPoint, this.wallEndPoint]);
                this.interactableEntity.getPosition.and.callFake(() => new Vector2D(Math.min(this.wallStartPoint.x, this.wallEndPoint.x), Math.min(this.wallStartPoint.z, this.wallEndPoint.z)));

                this.wallsHandler.getAnchors.and.returnValue([this.wallStartPoint, this.wallEndPoint]);

                this.uiUtils.getWallUnderCursor.and.returnValue(this.wall);

                const startCursorPosition = new Vector2D(1, 2);

                this.movingMode.handleMouseMove(startCursorPosition);
                this.movingMode.handleMouseDown(startCursorPosition);
            });

            //             +
            //             |
            //    +        o
            //    |        |       +
            //    o   =1>  +  =2>  |
            //    |                o
            //    +                |
            //                     +
            it('correctly calculates delta for dragged wall when wall has not been restricted in previous movement step', function () {
                let desiredCursorPosition;

                // step 1
                desiredCursorPosition = new Vector2D(2, 0);
                this.movingMode.handleMouseMove(desiredCursorPosition, this.event);
                expect(this.interactableEntity.move).toHaveBeenCalledWith(
                    this.auxiliaryPointsHandler, new Vector2D(1, -2), undefined,
                );

                // emulate case when wall is moved to desired position
                this.wallStartPoint.x = 2;
                this.wallStartPoint.z = -1;
                this.wallEndPoint.x = 2;
                this.wallEndPoint.z = 1;

                // step 2
                desiredCursorPosition = new Vector2D(-2, 2);
                this.movingMode.handleMouseMove(desiredCursorPosition, this.event);
                expect(this.interactableEntity.move).toHaveBeenCalledWith(
                    this.auxiliaryPointsHandler, new Vector2D(-4, 2), undefined,
                );
            });

            //                                 +
            //                                 |
            //    +         +                  o
            //    |         |          +       |
            //    o   =1>   |··o  =2>  |  =3>  +
            //    |         |          |
            //    +         +          |
            //                         +
            //                         ·
            //                         o
            it('correctly calculates delta for dragged wall when wall has been restricted in previous movement step', function () {
                let desiredCursorPosition;

                // step 1
                desiredCursorPosition = new Vector2D(4, 2);
                this.movingMode.handleMouseMove(desiredCursorPosition, this.event);
                expect(this.interactableEntity.move).toHaveBeenCalledWith(
                    this.auxiliaryPointsHandler, new Vector2D(3, 0), undefined,
                );

                // emulate case when anchor has been restricted from be moved to desired position
                this.wallStartPoint.x = 3; // desired is 4
                this.wallStartPoint.z = 1;
                this.wallEndPoint.x = 3; // desired is 4
                this.wallEndPoint.z = 3;

                // step 2
                desiredCursorPosition = new Vector2D(0, 3);
                this.movingMode.handleMouseMove(desiredCursorPosition, this.event);
                expect(this.interactableEntity.move).toHaveBeenCalledWith(
                    this.auxiliaryPointsHandler, new Vector2D(-3, 1), undefined,
                );
            });

            it('emits entityUnselected event on click on void canvas area', function () {
                const cursorPosition = new Vector2D(5, 5);
                this.movingMode.hoveredEntity = undefined;
                this.movingMode.handleMouseDown(cursorPosition, this.event);

                expect(this.events.emit).toHaveBeenCalledWith(RoomProfileEvents.entityUnselected);
            });
        });
    });
});

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants