[Qt-creator] Suggestions for 'new class' dialog

Kevin André hyperquantum at gmail.com
Tue Dec 15 17:22:17 CET 2020


On Tue, Dec 8, 2020 at 5:19 PM Eike Ziller <Eike.Ziller at qt.io> wrote:
>
> > On Dec 8, 2020, at 16:43, Kevin André <hyperquantum at gmail.com> wrote:
> >
> > On Tue, Dec 8, 2020 at 9:43 AM Eike Ziller <Eike.Ziller at qt.io> wrote:
> >>
> >>> On Dec 8, 2020, at 00:27, Kevin André <hyperquantum at gmail.com> wrote:
> >>>
> >>> Every time I use the dialog for adding a new class, there is still a
> >>> lot that I need to do manually after the files were generated:
> >>>
> >>> 1. Add cpp file and often the header file as well to CMakeLists.txt
> >>
> >> Unfortunately automatically adapting CMakeLists.txt files is a bit difficult.
> >
> > If it is only "a bit" difficult, then it's doable ;-)
>
> I suppose the prerequisite would be a CMake parser (at least a minimal one), which we don’t have. After that there is the problem of finding out how/where to add the file. Often enough CMake files don’t call the standard CMake functions for that directly, only indirectly via custom functions...

I think it could be done without understanding the structure of a
CMake file, but with some kind of pattern matching instead. Try to
emulate what a person would do when a new file is to be added: find
out where the pre-existing source files are in the CMake file, and
insert the name of the new file using the same pattern used for the
existing files. This would of course require that there are at least a
few pre-existing source files in the CMake file that you can look for.
Usually that is the case, unless it's a brand-new or a really tiny
project. In the latter case Qt Creator could still say "sorry, I could
not figure it out, you will have to add the file to CMakeLists.txt
yourself" like it does now.

It's true that often CMake files use their own functions or variables
for mentioning source files. But I think it's not unreasonable to
assume that the names of related source files will be grouped closely
together in some way.
Examples:

1)
  add_executable(MyProject abc.cpp mno.cpp rst.cpp uvw.cpp)

2)
  set(MYPROJECT_SOURCES
    abc.cpp
    mno.cpp
    rst.cpp
    uvw.cpp)

3)
  myfunction(abc.cpp)
  myfunction(mno.cpp)
  myfunction(rst.cpp)
  myfunction(uvw.cpp)

In each of the examples you could search the CMake file for (most of)
the names of pre-existing source files "abc.cpp", "rst.cpp", "uvw.cpp"
and "mno.cpp", and discover that they are close together and separated
by an identical string. In the first example, the separator consists
of just a single space character. The second example has a newline
followed by a few spaces as the common separator. The separator in the
third example is a bit more complicated; it is ")" followed by a
newline, some spaces, and "myfunction(". Adding a new file would then
be a matter of deciding after which pre-existing source file you would
want to insert (you may wish to keep file names sorted alphabetically
if they already are), followed by inserting the name of the new file
together with an extra separator string at that specific location.

How do you know what pre-existing files to look for in CMakeLists.txt?
Most likely this information is already provided by the CMake file
API. The projects view already displays projects and their source
files. And what project to add the new file to is specified in the
wizard.

There may be some complications. Files may be using a directory prefix:

 set(MYPROJECT_SOURCES
    src/a.cpp
    src/g.cpp
    src/k.cpp
    src/w.cpp)

In this case you could search the CMake file for the plain source file
name, like "a.cpp", and then look at the preceding text and discover
that the prefix "src/" matches the file's parent directory in the file
system. So in this case it can be deduced that a new file "e.cpp"
should be added as "src/e.cpp".

Then, maybe not all files are in the same location in the CMake file:

  add_executable(MyProject src/main.cpp ${MYPROJECT_SOURCES})

In this case "main.cpp" is separated from the other source files. I
think this could be handled by not requiring that 100% of the files
are grouped close together.

Another possible complication: inconsistent whitespace usage in the
CMake file. There might be an extra space somewhere, or a tab
character instead of one or more spaces. This means that the separator
string between the names of pre-existing files could sometimes vary a
little bit. This could be handled by matching whitespace more
generally when searching for the location of file names, treating any
combination of space characters and tab characters as just a single
occurrence of white space. When it's time to add the name of the new
file, pick the exact separator string that is used in the majority of
the cases or pick one at random.

One more difficulty I can think of: more than one CMake file may be
involved. How do you know which one you need to change? I suggest to
look at all of them, and simply search for a combination of
pre-existing source files that is convincing enough. It's possible
that the new file needs to be inserted in more than one location. For
example, a source file may be included in both the main project
executable and some unit/integration test executable that consists of
multiple files. Qt Creator could then propose to add the file in both
locations.

Of course, things could still go wrong. So I would suggest showing a
diff of the CMake file(s) to the user first and asking for
confirmation before actually applying each of the changes.

> >>> 4. Change naming of include guards (add prefix)
> >>> 5. Remove comment "// MYCLASS_H" at the #endif line

> >>> 4. It would be really great if a heuristic could figure out the naming
> >>> scheme for include guards from existing header files in the same
> >>> directory.
> >>>
> >>> 5. I wouldn't mind the comment so much if I didn't have to fix the
> >>> name of the include guard several times for each header.

> >> 4+5: Yes, though we usually don’t like magic so much, so an explicit setting providing a template would be preferred IMO.
> >
> > You mean something like this: a project setting "include guard naming"
> > with a default value like "%HEADERNAMEWITHOUTEXTENSION%_H" that I
> > could change to "MYPREFIX_%HEADERNAMEWITHOUTEXTENSION%_H"?
>
> Something like that.

Okay, I added QTCREATORBUG-25117 for this.


More information about the Qt-creator mailing list