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

No generated prototype for function with multi-line parameters in unsaved sketch #1800

Open
3 tasks done
per1234 opened this issue Dec 12, 2021 · 2 comments
Open
3 tasks done
Assignees
Labels
criticality: medium Of moderate impact topic: build-process Related to the sketch build process topic: code Related to content of the project itself type: imperfection Perceived defect in any part of project

Comments

@per1234
Copy link
Contributor

per1234 commented Dec 12, 2021

Describe the problem

In order to make it easier for beginners to get started with writing Arduino sketches, and for the convenience of all users, Arduino CLI automatically generates and adds prototypes for functions defined in a .ino file of a sketch.

An Arduino IDE editor tab can be in one of two states:

  • Saved: the contents of the file on disk matches the content in the editor buffer
    • The editor will always be in this state if the "Auto save" feature is enabled.
  • Dirty: the contents of the file on disk differs from the content staged in the editor buffer.
    • This is indicated by the presence of a ⬤ at the right side of the editor tab.

Function prototypes are not generated under the following conditions:

  • The function's parameter list spans multiple lines
  • The sketch is in an unsaved (AKA "dirty") state

🐛 Compilation of the sketch fails spuriously.

To reproduce

  1. Select File > Preferences from the Arduino IDE menus.
  2. Uncheck the box next to "☐ Auto save".
  3. Click the "OK" button.
  4. Create the following sketch:
    void setup() {
      foo(1, 2);
    }
    void loop() {}
    void foo(int bar,
             int baz) {}
    ⚠️ Do not save.
  5. Select Sketch > Verify/Compile from the Arduino IDE menus.

🐛 Compilation fails unexpectedly:

C:\Users\per\Documents\Arduino\sketch_dec11b\sketch_dec11b.ino: In function 'void setup()':
C:\Users\per\Documents\Arduino\sketch_dec11b\sketch_dec11b.ino:2:3: error: 'foo' was not declared in this scope
   // put your setup code here, to run once:
   ^~~
C:\Users\per\Documents\Arduino\sketch_dec11b\sketch_dec11b.ino:2:3: note: suggested alternative: 'feof'
   // put your setup code here, to run once:
   ^~~
   feof
Compilation error: exit status 1}

(Outdated sketch source in compilation output tracked here: https://github.com/arduino/arduino-cli/issues/1185)

🐛 Note that the preprocessed sketch program does not contain a function prototype for void foo(int, int):

#include <Arduino.h>
#line 1 "C:\\Users\\per\\Documents\\Arduino\\sketch_dec11b\\sketch_dec11b.ino"
#line 1 "C:\\Users\\per\\Documents\\Arduino\\sketch_dec11b\\sketch_dec11b.ino"
void setup();
#line 4 "C:\\Users\\per\\Documents\\Arduino\\sketch_dec11b\\sketch_dec11b.ino"
void loop();
#line 1 "C:\\Users\\per\\Documents\\Arduino\\sketch_dec11b\\sketch_dec11b.ino"
void setup() {
  foo(1, 2);
}
void loop() {}
void foo(int bar,
         int baz) {}

If you compile the identical sketch while it is in a saved state, the function prototype is generated as expected 🙂, so this is not about a fundamental limitation of the prototype generation system of Arduino CLI:

#include <Arduino.h>
#line 1 "C:\\Users\\per\\Documents\\Arduino\\sketch_dec11b\\sketch_dec11b.ino"
#line 1 "C:\\Users\\per\\Documents\\Arduino\\sketch_dec11b\\sketch_dec11b.ino"
void setup();
#line 4 "C:\\Users\\per\\Documents\\Arduino\\sketch_dec11b\\sketch_dec11b.ino"
void loop();
#line 5 "C:\\Users\\per\\Documents\\Arduino\\sketch_dec11b\\sketch_dec11b.ino"
void foo(int bar, int baz);
#line 1 "C:\\Users\\per\\Documents\\Arduino\\sketch_dec11b\\sketch_dec11b.ino"
void setup() {
  foo(1, 2);
}
void loop() {}
void foo(int bar,
         int baz) {}

Expected behavior

Prototypes for functions in .ino files are always generated.

Arduino CLI version

Original report

0.20.2, bundled with Arduino IDE a8ae0bb

Last verified with

0.36.0-rc.1, bundled with Arduino IDE aa9b10d

Operating system

Windows

Operating system version

  • Windows 10
  • Windows 11

Additional context

This issue does not occur in Arduino IDE 1.8.16


Originally reported by @UKHeliBob at https://forum.arduino.cc/t/auto-format-using-clang-format-file-produces-code-that-cannot-be-compiled/934610

Related

Workaround

Add a prototype for the function in the sketch before the first reference:

void foo(int bar, int baz);
void setup() {
  foo(1, 2);
}
void loop() {}
void foo(int bar,
         int baz) {}

- OR -

Save the sketch before compiling.

Issue checklist

  • I searched for previous reports in the issue tracker
  • I verified the problem still occurs when using the nightly build
  • My report contains all necessary details
@per1234 per1234 added topic: code Related to content of the project itself type: imperfection Perceived defect in any part of project labels Dec 12, 2021
@ubidefeo ubidefeo added the criticality: medium Of moderate impact label May 13, 2022
@fstasi fstasi assigned kittaakos and cmaglie and unassigned fstasi May 27, 2022
@kittaakos
Copy link
Contributor

kittaakos commented Jun 2, 2022

I went through the steps and found the followings:

I did:

  • Create a new sketch,
  • Disable auto-save,
  • Make sure the LS is running,
  • Copy-paste the snippet, and
  • Compile
Monosnap.screencast.2022-06-02.17-25-30.mp4

First off, the LS unexpectedly complains about the missing foo when I paste the snippet. The IDE2 is not involved in this part. If absent foo is a problem for both the LS and the CLI compiler, the bug could be outside the IDE2 code-base.

After the compile request, the IDE2 frontend (FE) correctly detects the dirty state and builds the following source-override map:

{
    "file:///private/var/folders/z1/xkw1yh5n7rz4n8djprp1mdn80000gn/T/.arduinoIDE-unsaved202252-19670-84ll7l.icynr/sketch_jun2a/sketch_jun2a.ino": "void setup() {\n     foo(1, 2);\n   }\n   void loop() {}\n   void foo(int bar,\n            int baz) {}"
}

The FE sends the source-override map as part of the compile request to the backend (BE). The BE builds this JSON object for the gRPC request and sends it to the CLI:

{
    "instance": {
        "id": 1
    },
    "fqbn": "arduino:avr:uno",
    "sketchPath": "/private/var/folders/z1/xkw1yh5n7rz4n8djprp1mdn80000gn/T/.arduinoIDE-unsaved202252-19670-84ll7l.icynr/sketch_jun2a",
    "showProperties": false,
    "preprocess": false,
    "buildCachePath": "",
    "buildPath": "",
    "buildPropertiesList": [],
    "warnings": "none",
    "verbose": false,
    "quiet": false,
    "vidPid": "",
    "jobs": 0,
    "librariesList": [],
    "optimizeForDebug": false,
    "exportDir": "",
    "clean": false,
    "createCompilationDatabaseOnly": false,
    "sourceOverrideMap": [
        [
            "sketch_jun2a.ino",
            "   void setup() {\n     foo(1, 2);\n   }\n   void loop() {}\n   void foo(int bar,\n            int baz) {}"
        ]
    ],
    "libraryList": []
}

FE: "void setup() {\n foo(1, 2);\n }\n void loop() {}\n void foo(int bar,\n int baz) {}"
BE: " void setup() {\n foo(1, 2);\n }\n void loop() {}\n void foo(int bar,\n int baz) {}"

The FE and BE content difference is odd but must not be crucial. 👆 I will investigate why there are two leading space characters in the BE version of the content, but I doubt this is the root cause of the defect.

/private/var/folders/z1/xkw1yh5n7rz4n8djprp1mdn80000gn/T/.arduinoIDE-unsaved202252-19670-84ll7l.icynr/sketch_jun2a/sketch_jun2a.ino: In function 'void setup()':
/private/var/folders/z1/xkw1yh5n7rz4n8djprp1mdn80000gn/T/.arduinoIDE-unsaved202252-19670-84ll7l.icynr/sketch_jun2a/sketch_jun2a.ino:2:6: error: 'foo' was not declared in this scope
   // put your setup code here, to run once:
      ^~~
/private/var/folders/z1/xkw1yh5n7rz4n8djprp1mdn80000gn/T/.arduinoIDE-unsaved202252-19670-84ll7l.icynr/sketch_jun2a/sketch_jun2a.ino:2:6: note: suggested alternative: 'feof'
   // put your setup code here, to run once:
      ^~~
      feof

Compilation error: exit status 1

Update:

I will investigate why there are two leading space characters in the BE version of the content, but I doubt this is the root cause of the defect.

The FE and BE contents are the same for the second attempt. I must have made a mistake while recording the screencast or documenting the step. I leave the original comment untouched, but below is the JSON of the second attempt.

{
    "instance": {
        "id": 1
    },
    "fqbn": "arduino:avr:uno",
    "sketchPath": "/private/var/folders/z1/xkw1yh5n7rz4n8djprp1mdn80000gn/T/.arduinoIDE-unsaved202252-19670-84ll7l.icynr/sketch_jun2a",
    "showProperties": false,
    "preprocess": false,
    "buildCachePath": "",
    "buildPath": "",
    "buildPropertiesList": [],
    "warnings": "none",
    "verbose": false,
    "quiet": false,
    "vidPid": "",
    "jobs": 0,
    "librariesList": [],
    "optimizeForDebug": false,
    "exportDir": "",
    "clean": false,
    "createCompilationDatabaseOnly": false,
    "sourceOverrideMap": [
        [
            "sketch_jun2a.ino",
            "void setup() {\n  foo(1, 2);\n}\nvoid loop() {}\nvoid foo(int bar,\n         int baz) {}"
        ]
    ],
    "libraryList": []
}

@per1234 per1234 transferred this issue from arduino/arduino-ide Jul 12, 2022
@per1234
Copy link
Contributor Author

per1234 commented Jul 12, 2022

Thanks so much for taking the time to investigate this @kittaakos!

Using the insight you shared, I am now able to reproduce the issue using Arduino CLI directly, so can verify that this is not anything related to the Arduino IDE code base. I have moved the issue to the appropriate repository.

Set up

$ arduino-cli version
arduino-cli.exe  Version: 0.25.0-rc1 Commit: 63b53c0f Date: 2022-07-12T01:46:05Z

$ mkdir /tmp/SourceOverridePrototypeGenBug

$ printf "void setup() {}\nvoid loop() {}\n" > "/tmp/SourceOverridePrototypeGenBug/SourceOverridePrototypeGenBug.ino"

$ arduino-cli daemon

Demo

Use grpcurl to run the following commands:

$ grpcurl \
  -plaintext \
  -import-path ./rpc \
  -proto cc/arduino/cli/commands/v1/commands.proto \
  127.0.0.1:50051 \
  cc.arduino.cli.commands.v1.ArduinoCoreService.Create

{
  "instance": {
    "id": 1
  }
}

$ grpcurl \
  -plaintext \
  -import-path ./rpc \
  -proto cc/arduino/cli/commands/v1/commands.proto \
  -d '{"instance": {"id": 1}}' \
  127.0.0.1:50051 \

$ grpcurl \
  -plaintext \
  -import-path ./rpc \
  -proto cc/arduino/cli/commands/v1/commands.proto \
  -d '{"instance": {"id": 1}, "fqbn": "arduino:avr:uno", "sketch_path": "/tmp/SourceOverridePrototypeGenBug", "source_override": [{"key": "SourceOverridePrototypeGenBug.ino", "value": "void setup() {\n  foo(1, 2);\n}\nvoid loop() {}\nvoid foo(int bar,\n         int baz) {}"}]}' \
  127.0.0.1:50051 \
  cc.arduino.cli.commands.v1.ArduinoCoreService.Compile

[...]
{
  "errStream": "QzpcVXNlcnNccGVyXEFwcERhdGFcTG9jYWxcVGVtcFxTb3VyY2VPdmVycmlkZVByb3RvdHlwZUdlbkJ1Z1xTb3VyY2VPdmVycmlkZVByb3RvdHlwZUdlbkJ1Zy5pbm86IEluIGZ1bmN0aW9uICd2b2lkIHNldHVwKCknOg0KQzpcVXNlcnNccGVyXEFwcERhdGFcTG9jYWxcVGVtcFxTb3VyY2VPdmVycmlkZVByb3RvdHlwZUdlbkJ1Z1xTb3VyY2VPdmVycmlkZVByb3RvdHlwZUdlbkJ1Zy5pbm86MjozOiBlcnJvcjogJ2Zvbycgd2FzIG5vdCBkZWNsYXJlZCBpbiB0aGlzIHNjb3BlDQogdm9pZCBsb29wKCkge30NCiAgIF5+fg0K"
}
[...]
ERROR:
  Code: Internal
  Message: exit status 1

$ grpcurl \
  -plaintext \
  -import-path ./rpc \
  -proto cc/arduino/cli/commands/v1/commands.proto \
  -d '{"instance": {"id": 1}, "fqbn": "arduino:avr:uno", "sketch_path": "/tmp/SourceOverridePrototypeGenBug", "source_override": [{"key": "SourceOverridePrototypeGenBug.ino", "value": "void setup() {\n  foo(1, 2);\n}\nvoid loop() {}\nvoid foo(int bar, int baz) {}"}]}' \
  127.0.0.1:50051 \
  cc.arduino.cli.commands.v1.ArduinoCoreService.Compile

[...]

$ echo "$?"
0

Notes

The sketch code compiles fine when it is saved to disk:

$ printf "void setup() {\n  foo(1, 2);\n}\nvoid loop() {}\nvoid foo(int bar,\n         int baz) {}" > "/tmp/SourceOverridePrototypeGenBug/SourceOverridePrototypeGenBug.ino"

$ arduino-cli compile --fqbn arduino:avr:uno "/tmp/SourceOverridePrototypeGenBug"
Sketch uses 444 bytes (1%) of program storage space. Maximum is 32256 bytes.
Global variables use 9 bytes (0%) of dynamic memory, leaving 2039 bytes for local variables. Maximum is 2048 bytes.


Used platform Version Path
arduino:avr   1.8.99  C:\Users\per\AppData\Local\Arduino15\packages\arduino\hardware\avr\1.8.99

@umbynos umbynos added the topic: build-process Related to the sketch build process label Feb 2, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
criticality: medium Of moderate impact topic: build-process Related to the sketch build process topic: code Related to content of the project itself type: imperfection Perceived defect in any part of project
Projects
None yet
Development

No branches or pull requests

6 participants