Skip to main content

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [List Home]
[cdt-dev] Multi-language support in the model and for preferences

While this is still fresh in my memory, I want to explain what I did in Photran to add Fortran elements to the C Model and for adding new core preferences. Comments are extremely welcome.

- For the model...

Everything inside our translation units is a subclass of

public abstract class FortranElement
	extends Parent
	implements ICElement, IParent, ISourceReference {...}

Yeah, not variables are not technically Parents, but it's not hurting anything.

One thing that would be nice would be to have a class somewhere between SourceManipulation and Parent. I ended up copying lots of methods directly out of SourceManipulation into FortranElement... I would have subclassed SourceManipulation instead of Parent, except our refactoring is not (will not be) done via ISourceManipulation, so it would be claiming we can do more than we really can.

I wanted our elements to have their own icons. I didn't want to add more stuff into CElementImageProvider. Generally speaking, when you're comparing based on type (which is happening all over the place in that file), you would be better off taking advantage of polymorphism/dynamic dispatch. (Comparison based on type is a typical "code smell"... see Fowler's Refactoring book, page 255.) My solution was to give each FortranElement a method

public ImageDescriptor getBaseImageDescriptor()

My only change to CElementImageProvider, then, was to add at the top of getBaseImageDescriptor:

if (celement instanceof FortranElement)
    return ((FortranElement)celement).getBaseImageDescriptor();

Theoretically, that method could be reduced to one line if every CElement did this. :-)

One architectural flaw with this is that FortranElements (which are in the core) must know what their icons are (which is typically the UI's problem). Maybe it would be better if the elements only knew their filename, and the CElementImageProvider used that to load an icon. Or it could reflectively look at the CElement class name and grab an icon with that name + ".gif", if it exists. I don't know. At any rate, there is a circular dependency between the core and the UI here, which needs to be dealt with.

Finally, I set the type field (setElementType()) to -1 in every FortranElement. Is there any advantage to telling the model what's a function, etc.? Similar to the above, I am not going to add more constants to ICElement, so if that type field is important, it should probably be eliminated, and tests against it should be replaced with polymorphic calls back to the CElement. And/or ICElementVisitor needs to become a real GoF Visitor (i.e., use double dispatch), and all of the gigantic switch statements on types (ChangeCollector#getAllTypesFromHierarchy, TypeSearchScope#add, CSearchScope#add, etc.) need to become visitor instantiations. On the other hand, if every language except C and C++ can just set the type to -1 or an existing constant and be satisfied, then everything's fine as-is. :-)

On a somewhat related topic, just out of curiosity, does the C/C++ Browsing perspective only use the model to populate itself, or does it use more than that? Even after setting the type fields logically (e.g., class inside a namespace inside a translation unit), it didn't magically populate itself... I only got a global namespace for each file. Obviously, I haven't tried to track down what's happening there... suggestions are welcome...

And do we have any hope of reusing the C indexer? Haven't looked at that either...

- Preferences

I want the core to be able to initialize all of its Fortran-specific preferences without telling it what they are. :-) So CCorePlugin.start has only one line added:

FortranPreferences.initializeDefaults(getPluginPreferences());

The FortranPreferences class is just a bunch of constants of type FortranPreference. Each FortranPreference has a setDefault(...) function. So FortranPreferences.initializeDefaults just reflectively calls setDefault on each of its fields. So adding a new Fortran preference is simply a matter of adding a new constant to that class. It gets its default value set automatically.

I don't think that will be an issue with multi-language support, since we'll be adding new plugins, each of which can set its own preference defaults however it wants. But I thought I'd mention it anyway.

Again, comments are welcome.

Jeff


Back to the top