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

My managed Build throws exceptions when openening multi configuration project property pages. #356

Closed
jantje opened this issue Apr 8, 2023 · 14 comments

Comments

@jantje
Copy link
Contributor

jantje commented Apr 8, 2023

When in my new MBS implementation, I open project properties->preprocessor include I get the stacktrace below

!ENTRY org.eclipse.jface 4 2 2023-04-08 17:28:27.379
!MESSAGE Problems occurred when invoking code from plug-in: "org.eclipse.jface".
!STACK 0
java.lang.NullPointerException: Cannot invoke "org.eclipse.cdt.core.settings.model.ICResourceDescription.getConfiguration()" because the return value of "org.eclipse.cdt.internal.ui.language.settings.providers.LanguageSettingsEntriesTab.getResDesc()" is null
	at org.eclipse.cdt.internal.ui.language.settings.providers.LanguageSettingsEntriesTab.getConfigurationDescription(LanguageSettingsEntriesTab.java:256)
	at org.eclipse.cdt.internal.ui.language.settings.providers.LanguageSettingsEntriesTab.getProviders(LanguageSettingsEntriesTab.java:1009)
	at org.eclipse.cdt.internal.ui.language.settings.providers.LanguageSettingsEntriesTab.updateTreeForEntries(LanguageSettingsEntriesTab.java:1038)
	at org.eclipse.cdt.internal.ui.language.settings.providers.LanguageSettingsEntriesTab.enableTabControls(LanguageSettingsEntriesTab.java:503)
	at org.eclipse.cdt.internal.ui.language.settings.providers.LanguageSettingsEntriesTab.createControls(LanguageSettingsEntriesTab.java:485)
	at org.eclipse.cdt.ui.newui.AbstractCPropertyTab.createControls(AbstractCPropertyTab.java:139)
	at org.eclipse.cdt.ui.newui.AbstractPage.loadTab(AbstractPage.java:1199)
	at org.eclipse.cdt.ui.newui.AbstractPage.loadExtensionsSynchronized(AbstractPage.java:1143)
	at org.eclipse.cdt.ui.newui.AbstractPage.createWidgets(AbstractPage.java:373)
	at org.eclipse.cdt.ui.newui.AbstractPage.contentForCDT(AbstractPage.java:359)
	at org.eclipse.cdt.ui.newui.AbstractPage.createContents(AbstractPage.java:256)
	at org.eclipse.jface.preference.PreferencePage.createControl(PreferencePage.java:244)
	at org.eclipse.jface.preference.PreferenceDialog.createPageControl(PreferenceDialog.java:1434)
	at org.eclipse.jface.preference.PreferenceDialog$8.run(PreferenceDialog.java:1197)
	at org.eclipse.core.runtime.SafeRunner.run(SafeRunner.java:45)
	at org.eclipse.jface.util.SafeRunnable.run(SafeRunnable.java:174)
	at org.eclipse.jface.preference.PreferenceDialog.showPage(PreferenceDialog.java:1189)
	at org.eclipse.ui.internal.dialogs.FilteredPreferenceDialog.showPage(FilteredPreferenceDialog.java:630)
	at org.eclipse.jface.preference.PreferenceDialog$5.lambda$0(PreferenceDialog.java:661)
	at org.eclipse.swt.custom.BusyIndicator.showWhile(BusyIndicator.java:67)
	at org.eclipse.jface.preference.PreferenceDialog$5.selectionChanged(PreferenceDialog.java:658)
	at org.eclipse.jface.viewers.StructuredViewer$3.run(StructuredViewer.java:821)
	at org.eclipse.core.runtime.SafeRunner.run(SafeRunner.java:45)
	at org.eclipse.jface.util.SafeRunnable.run(SafeRunnable.java:174)
	at org.eclipse.jface.viewers.StructuredViewer.firePostSelectionChanged(StructuredViewer.java:818)
	at org.eclipse.jface.viewers.StructuredViewer.handlePostSelect(StructuredViewer.java:1191)
	at org.eclipse.swt.events.SelectionListener$1.widgetSelected(SelectionListener.java:84)
	at org.eclipse.jface.util.OpenStrategy.firePostSelectionEvent(OpenStrategy.java:284)
	at org.eclipse.jface.util.OpenStrategy$1.lambda$1(OpenStrategy.java:438)
	at org.eclipse.swt.widgets.RunnableLock.run(RunnableLock.java:40)
	at org.eclipse.swt.widgets.Synchronizer.runAsyncMessages(Synchronizer.java:132)
	at org.eclipse.swt.widgets.Display.runAsyncMessages(Display.java:4029)
	at org.eclipse.swt.widgets.Display.readAndDispatch(Display.java:3645)
	at org.eclipse.jface.window.Window.runEventLoop(Window.java:823)
	at org.eclipse.jface.window.Window.open(Window.java:799)
	at org.eclipse.ui.dialogs.PropertyDialogAction.run(PropertyDialogAction.java:155)
	at org.eclipse.jface.action.Action.runWithEvent(Action.java:474)
	at org.eclipse.jface.commands.ActionHandler.execute(ActionHandler.java:121)
	at org.eclipse.ui.internal.handlers.E4HandlerProxy.execute(E4HandlerProxy.java:97)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/java.lang.reflect.Method.invoke(Method.java:568)
	at org.eclipse.e4.core.internal.di.MethodRequestor.execute(MethodRequestor.java:58)
	at org.eclipse.e4.core.internal.di.InjectorImpl.invokeUsingClass(InjectorImpl.java:317)
	at org.eclipse.e4.core.internal.di.InjectorImpl.invoke(InjectorImpl.java:251)
	at org.eclipse.e4.core.contexts.ContextInjectionFactory.invoke(ContextInjectionFactory.java:173)
	at org.eclipse.e4.core.commands.internal.HandlerServiceHandler.execute(HandlerServiceHandler.java:156)
	at org.eclipse.core.commands.Command.executeWithChecks(Command.java:488)
	at org.eclipse.core.commands.ParameterizedCommand.executeWithChecks(ParameterizedCommand.java:485)
	at org.eclipse.e4.core.commands.internal.HandlerServiceImpl.executeHandler(HandlerServiceImpl.java:213)
	at org.eclipse.e4.ui.bindings.keys.KeyBindingDispatcher.executeCommand(KeyBindingDispatcher.java:308)
	at org.eclipse.e4.ui.bindings.keys.KeyBindingDispatcher.press(KeyBindingDispatcher.java:580)
	at org.eclipse.e4.ui.bindings.keys.KeyBindingDispatcher.processKeyEvent(KeyBindingDispatcher.java:647)
	at org.eclipse.e4.ui.bindings.keys.KeyBindingDispatcher.filterKeySequenceBindings(KeyBindingDispatcher.java:439)
	at org.eclipse.e4.ui.bindings.keys.KeyBindingDispatcher$KeyDownFilter.handleEvent(KeyBindingDispatcher.java:96)
	at org.eclipse.swt.widgets.EventTable.sendEvent(EventTable.java:89)
	at org.eclipse.swt.widgets.Display.filterEvent(Display.java:1286)
	at org.eclipse.swt.widgets.Widget.sendEvent(Widget.java:1065)
	at org.eclipse.swt.widgets.Widget.sendEvent(Widget.java:1090)
	at org.eclipse.swt.widgets.Widget.sendEvent(Widget.java:1075)
	at org.eclipse.swt.widgets.Widget.sendKeyEvent(Widget.java:1117)
	at org.eclipse.swt.widgets.Widget.sendKeyEvent(Widget.java:1113)
	at org.eclipse.swt.widgets.Widget.wmSysChar(Widget.java:2351)
	at org.eclipse.swt.widgets.Control.WM_SYSCHAR(Control.java:5451)
	at org.eclipse.swt.widgets.Control.windowProc(Control.java:4821)
	at org.eclipse.swt.widgets.Tree.windowProc(Tree.java:6142)
	at org.eclipse.swt.widgets.Display.windowProc(Display.java:5022)
	at org.eclipse.swt.internal.win32.OS.DispatchMessage(Native Method)
	at org.eclipse.swt.widgets.Display.readAndDispatch(Display.java:3640)
	at org.eclipse.e4.ui.internal.workbench.swt.PartRenderingEngine$5.run(PartRenderingEngine.java:1155)
	at org.eclipse.core.databinding.observable.Realm.runWithDefault(Realm.java:338)
	at org.eclipse.e4.ui.internal.workbench.swt.PartRenderingEngine.run(PartRenderingEngine.java:1046)
	at org.eclipse.e4.ui.internal.workbench.E4Workbench.createAndRunUI(E4Workbench.java:155)
	at org.eclipse.ui.internal.Workbench.lambda$3(Workbench.java:643)
	at org.eclipse.core.databinding.observable.Realm.runWithDefault(Realm.java:338)
	at org.eclipse.ui.internal.Workbench.createAndRunWorkbench(Workbench.java:550)
	at org.eclipse.ui.PlatformUI.createAndRunWorkbench(PlatformUI.java:171)
	at org.eclipse.ui.internal.ide.application.IDEApplication.start(IDEApplication.java:152)
	at org.eclipse.pde.internal.junit.runtime.NonUIThreadTestApplication.runApp(NonUIThreadTestApplication.java:53)
	at org.eclipse.pde.internal.junit.runtime.NonUIThreadTestApplication.start(NonUIThreadTestApplication.java:48)
	at org.eclipse.equinox.internal.app.EclipseAppHandle.run(EclipseAppHandle.java:203)
	at org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher.runApplication(EclipseAppLauncher.java:136)
	at org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher.start(EclipseAppLauncher.java:104)
	at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:402)
	at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:255)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/java.lang.reflect.Method.invoke(Method.java:568)
	at org.eclipse.equinox.launcher.Main.invokeFramework(Main.java:659)
	at org.eclipse.equinox.launcher.Main.basicRun(Main.java:596)
	at org.eclipse.equinox.launcher.Main.run(Main.java:1467)
	at org.eclipse.equinox.launcher.Main.main(Main.java:1440)

To Reproduce

  1. In a CDT development environment add the repository https://github.com/Sloeber/arduino-eclipse-plugin.git

  2. Close all Sloeber projects except for the ones starting with io.sloeber.autoBuild

  3. Run the test /io.sloeber.autoBuild.test/src/io/sloeber/autoBuild/regression/CreateBasicProjects.java in debug not in the main thread keeping the thread running.
    afbeelding

  4. If you have a compatible make and gcc in your path all projects should have build fine (but for reproducing this issue that is not important)

  5. open the project properties of one of the created projects and open the preprocessor and include paths
    afbeelding
    Next to the error you will get the stacktrace listed above.

When I step through the code everything seems fine here.
afbeelding
The last selected configuration variable is the one that should be selected and the page holds 2 configurations.
(for my pages I currently work around this issue by selecting the first of the list of configs and I do not see any negative consequences of doing so -apart from only having the possibility of changing the first configuration-)

When going deeper I come to pathsettingsProvider that contains null;
afbeelding

I learned that the behaviour changes with different implementations of
public CFolderData getRootFolderData() from CConfigurationData
But I have no idea whether this is the root cause or a side effect

Expected behavior
The configuration specific info is given.

Screenshots
see above

Desktop (please complete the following information):

  • OS: windows

Background info
This is into relation with the discussion here:
#337
I'm assuming I'm doing something "wrong" but I can't figure out what.

@jantje
Copy link
Contributor Author

jantje commented Apr 17, 2023

I'm kind of like stuck on this issue.
Any advice on how to progress this issue is really appreciated.

@jantje
Copy link
Contributor Author

jantje commented May 24, 2023

@jonahgraham
Can you give me some input that can get me back on track in regards to this issue?
Thanks

@jonahgraham
Copy link
Member

Close all Sloeber projects except for the ones starting with io.sloeber.autoBuild

I don't see any projects with that name
image

@jonahgraham
Copy link
Member

I see that this branch has the project - https://github.com/Sloeber/arduino-eclipse-plugin/tree/%231126_support_for_creating_library_archives - I'll try it.

@jonahgraham
Copy link
Member

(Minor nit - having branch names that have or start with # makes it extra hard to work with those branches as you can't type git checkout #1126_support_for_creating_library_archives in many shells as # is a comment character)

@jonahgraham
Copy link
Member

From trying to read your stack traces I am unsure as to what is going on wrong here. Let me know when you have a chance to update reproduction instructions and I can have a closer look again.

@jantje
Copy link
Contributor Author

jantje commented May 29, 2023

Thanks for looking at this.
I should have specified the branch. Sorry for that.
as to starting with #. I was told a long time ago to do so. I've noticed eclipse started treating the # as a comment even in the comments.
As to not having a .project. I'll add it.
The extra stuff 😨 I have no clue what it is or where this comes from. I'll remove it.

From trying to read your stack traces I am unsure as to what is going on wrong here

I've been looking for clues myself many days and I simply do not get (even not what is going on).

->>Did the changes in the repro and tested again. getResDesc() keeps on returning null

@jonahgraham
Copy link
Member

I have spent as long as I can afford to on this issue. Unfortunately I cannot understand why this is happening.

@jantje
Copy link
Contributor Author

jantje commented May 29, 2023

I have spent as long as I can afford to on this issue. Unfortunately I cannot understand why this is happening.

Nor can I.
Lets hope time will bring ideas.
I'm getting close to something "workable" with the AutoBuild but this issue is an absolute show stopper as none of the CDT stuff is working.

@jantje
Copy link
Contributor Author

jantje commented Jun 19, 2023

I got it to work 😄
As I expected getRootFolderData is involved.
The working code is :

    @Override
    public CFolderData getRootFolderData() {
        CDataFactory factory = CDataFactory.getDefault();
        return factory.createFolderData(this, null, null, false, new Path(SLACH));
    }

The code below generates the issue

    @Override
    public CFolderData getRootFolderData() { 
           CDataFactory factory = CDataFactory.getDefault();
            return factory.createFolderData(this, null, null, false, myProject.getFullPath());
    }

I'm not sure what to do with this issue. I had hoped to be able to improve the documentation but all I can say right now is "this works, no clue why"

PS: I tried to see whether I could see a difference in the "path and Symbols" in project properties but it is not yet visible in AutoBuild.

@jantje
Copy link
Contributor Author

jantje commented Jun 21, 2023

I finally got AutoBuild to work nicely with configuration changes in project properties
to do so I added a field to contain the rootFolder ID
private String myRootFolderID = CDataUtil.genId("io.sloeber.autoBuild.configurationDescrtion.rootFolder"); //$NON-NLS-1$;
In the copy constructor I copy the ID (this is absolutely necessary) but not myRootFolderData

    public AutoBuildConfigurationDescription(ICConfigurationDescription cfgDescription,
            AutoBuildConfigurationDescription autoBuildConfigBase) {
....
        myRootFolderID = autoBuildConfigBase.myRootFolderID;

The getRootFolderData uses the myRootFolderID to create a CFolderData object

    @Override
    public CFolderData getRootFolderData() {
        if (myRootFolderData == null) {
            CDataFactory factory = CDataFactory.getDefault();
            myRootFolderData = factory.createFolderData(this, null, myRootFolderID, false, Path.ROOT);
        }
        return myRootFolderData;
    }

getResourceDatas needs to add myRootFolderData to the list. Below is my current code which I expect to change as I still don't know what this is used for.

    @Override
    public CResourceData[] getResourceDatas() {
        CResourceData datas[] = new CResourceData[1];
        datas[0] = getRootFolderData();
        //        CResourceData datas[] = new CResourceData[0];
        return datas;

    }

Though not a bug fix I would like to change the code below

CFolderData baseRootFolderData = base.getRootFolderData();
fRootFolderData = copyFolderData(baseRootFolderData.getPath(), baseRootFolderData, clone);
addRcData(fRootFolderData);
CResourceData[] rcDatas = filterRcDatasToCopy(base);
for (int i = 0; i < rcDatas.length; i++) {
CResourceData rcData = rcDatas[i];
if (baseRootFolderData == rcData)
continue;
if (rcData instanceof CFolderData)
addRcData(copyFolderData(rcData.getPath(), (CFolderData) rcData, clone));
else if (rcData instanceof CFileData)
addRcData(copyFileData(rcData.getPath(), (CFileData) rcData, clone));
}

to something in the style of

		CFolderData baseRootFolderData = base.getRootFolderData();
		fRootFolderData = copyFolderData(baseRootFolderData.getPath(), baseRootFolderData, clone);

		CResourceData[] rcDatas = filterRcDatasToCopy(base);

                boolean foundBaseRootFolderData=false;
		for (int i = 0; i < rcDatas.length; i++) {
			CResourceData rcData = rcDatas[i];
			if (baseRootFolderData == rcData){
                               foundBaseRootFolderData=true;
                         }

			if (rcData instanceof CFolderData)
				addRcData(copyFolderData(rcData.getPath(), (CFolderData) rcData, clone));
			else if (rcData instanceof CFileData)
				addRcData(copyFileData(rcData.getPath(), (CFileData) rcData, clone));
		}
               if(!foundBaseRootFolderData){
                   throw exception
               }

The benefit of this is: instead of partially fixing the coding problem the coding problem gets highlighted.
I'm willing to create a PR to see what testing thinks of this change.

@jantje
Copy link
Contributor Author

jantje commented Sep 2, 2023

The problem still pops up from time to time and I think I'm on to something
AbstractPage contains 2 static fields resd and lastSelectedCfg

private static ICResourceDescription resd = null;
private static ICConfigurationDescription[] cfgDescs = null;
private static ICConfigurationDescription lastSelectedCfg = null;

It is not clear to me why there are 2 fields as they seem conceptually the same (technically they are a different types)
As getResDesc() basically returns resd this piece of code compare the outcome of the respective getId() calls

String id1 = getResDesc() == null ? null : getResDesc().getId();
lastSelectedCfg = cfgDescs[selectionIndex];
String id2 = lastSelectedCfg.getId();
if (id2 != null && !id2.equals(id1)) {
cfgChanged(lastSelectedCfg);
}

Therefore the code compares the id's of 2 different types
As in my test (using a project property page) resd is a CFolderDescription and lastSelectedCfg is a CConfigurationDescription

For these ID's to match up (which they do not do in my case resulting in multiple calls to cfgChanged) I probably need special code.
But to me this id comparison from different classes seems doggy. But I've been wrong before.

input is welcomed

@jantje
Copy link
Contributor Author

jantje commented Nov 24, 2023

After months completely focussing on this issue I can now say: "I finally fixed this issue".
In the end it turned out that during cloning of a object provided to CDT the id copy was not executed like I thought.
Note that the current document does not even get to explaining why the id's are needed.

I did an effort to write down what I learned about the CDT projectDescriptions and configuration descriptions but I kept getting distracted so I'll stop doing it (and get on with what I actually was doing).

If someone asks for a specific explanation I'm willing to provide that info.

The doc is here https://docs.google.com/document/d/19Bhly15MPTvffmI880pTmYesLyXPFIU-R4lYY65J-RQ

Anyway I copied the conclusion below

The current implementation of CConfigurationDescription shows there has been an enormous effort put into making the code work. Many of the failed efforts still have code remainers in the current code.
This makes it very hard to understand what is going on and do problem solving, and that makes the code unmaintainable.

Moreover a part of the code is not reentry/thread safe (I know I haven’t talked about thread safety yet) and may therefore cause issues on a multiprocessor computer.

As the code places requirements on the undocumented SPI anyone who wants to provide the service will struggle (that is very few people I know)

I think an implementation of CConfigurationDescription that clones the actual storage objects at construction and as such is writable from the start and that would delegate the get and set calls to the actual implementers (no caching) would be easy to implement and has a chance of actually working.

@jantje jantje closed this as completed Nov 24, 2023
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