Errors for a node

Hi all,

I would like to check if a node and its descendants are valid (no errors).

Therefore I would like to know if there is a way to get errors for a node?

Thank you in advance.

Best regards,

Josef

11 comments
Comment actions Permalink

Hi Josef,

interesting, yesterday I had exactly the same task in the context of an intention. I found a solution:

https://github.com/JetBrains/MPS/tree/master/core/kernel/source_gen/jetbrains/mps/checkers 

I think this package will solve your task, too.

Best regards,
Holger

 

1
Comment actions Permalink

Hi Holger,

 

Can you elaborate on how to do this?  I have taken a look at the code in the paackage you mention,but it is unclear to me how I can get the errors, starting from a node that I have.

Jos

1
Comment actions Permalink

Hi Jos,

we have something along the lines of the following code to invoke certain model checkers via API:

// false => don't check stubs (whatever that means exactly)
ModelCheckerBuilder mcBuilder = new ModelCheckerBuilder(false);

// look into getSpecificCheckers to see how you can influence what checkers you get ... you can also instantiate the checkers manually, I guess
list<IChecker<?, ?>> specificCheckers = ModelCheckerSettings.getInstance().getSpecificCheckers(mpsProject);

IAbstractChecker<ModelCheckerBuilder.ItemsToCheck, IssueKindReportItem> modelChecker = mcBuilder.createChecker(specificCheckers);
ModelCheckerBuilder.ItemsToCheck itemsToCheck = new ItemsToCheck();
itemsToCheck.models.add(modelToCheck);
CollectConsumer<IssueKindReportItem> issues = new CollectConsumer();
SRepository repo = mpsProject.getRepository();
// pmSub is some progress monitor if you want to show this to the user
modelChecker.check(itemsToCheck, repo, issues, pmSub);

 

This doesn't work headless due to some class loading issues. When run headless, we just call the individual checkers manually:

set<NodeReportItem> errors = new hashset<NodeReportItem>
MPSModuleRepository mpsModuleRepo = MPSModuleRepository.getInstance(); //getInstance() is deprecated, we haven't updated it yet
LanguageErrorsComponent lec = new LanguageErrorsComponent(m);

ConstraintsChecker cc = new ConstraintsChecker();
RefScopeChecker rsc = new RefScopeChecker();
TypesystemChecker tsc = new TypesystemChecker();

// n is the node to check
cc.checkNodeInEditor(n, lec, mpsModuleRepo);
rsc.checkNodeInEditor(n, lec, mpsModuleRepo);
errors.addAll(lec.getErrors());

// don't know the details why this checker has a different API to perform the checks
Set<NodeReportItem> tscErrors = tsc.getErrors(n, mpsModuleRepo);
errors.addAll(tscErrors);

I had to change the code a bit for this post since it is distributed in a local API, so above code is untested in this form. Hope it still helps.

 

 

 

1
Comment actions Permalink

Hi,  tnx for the answer.  I applied the code above to my situation.    I now keep getting NullPointerExceptions in the check method somewhere inside AggeregateChecker.check(). This happen both for models with and without problems,

Just to be clear I only tried the first option.

0
Comment actions Permalink

Sorry to hear that. Can you share the stacktrace?

How do you run the code? Via an action, an intention or another way?

0
Comment actions Permalink

Here is the stacktrace.  I trigger the code through a self-implemented Swing button.

 

[ 424014]   INFO - s.plugins.PluginLoaderRegistry - Unloading of 1 plugins took 0.204 s
[ 424061]   INFO - s.plugins.PluginLoaderRegistry - Loading of 1 plugins took 0.012 s
[ 428514]  ERROR - llij.ide.plugins.PluginManager - null
java.lang.NullPointerException
        at jetbrains.mps.checkers.AggregatingChecker.check(AggregatingChecker.java:23)
        at jetbrains.mps.checkers.SkippingChecker.check(SkippingChecker.java:21)
        at jetbrains.mps.checkers.ModelCheckerBuilder$1.check(ModelCheckerBuilder.java:142)
        at jetbrains.mps.checkers.ModelCheckerBuilder$1.check(ModelCheckerBuilder.java:114)
        at GegevensDemo.editor.GegevensModelDemo_EditorBuilder_a$4$1.visit(GegevensModelDemo_EditorBuilder_a.java:311)
        at GegevensDemo.editor.GegevensModelDemo_EditorBuilder_a$4$1.visit(GegevensModelDemo_EditorBuilder_a.java:1)
        at jetbrains.mps.internal.collections.runtime.IVisitor.invoke(IVisitor.java:12)
        at jetbrains.mps.internal.collections.runtime.IterableUtils.visitAll(IterableUtils.java:16)
        at jetbrains.mps.internal.collections.runtime.AbstractSequence.visitAll(AbstractSequence.java:80)
        at GegevensDemo.editor.GegevensModelDemo_EditorBuilder_a$4.exec(GegevensModelDemo_EditorBuilder_a.java:284)
        at Simulatie.Swing.BadButtons$1$1.run(BadButtons.java:18)
        at jetbrains.mps.smodel.WorkbenchModelAccess$CommandRunnable.lambda$run$0(WorkbenchModelAccess.java:449)
        at jetbrains.mps.smodel.WriteActionDispatcher.run(WriteActionDispatcher.java:39)
        at jetbrains.mps.smodel.WorkbenchModelAccess.lambda$runWriteAction$1(WorkbenchModelAccess.java:105)
        at com.intellij.openapi.application.impl.ApplicationImpl.runWriteAction(ApplicationImpl.java:1010)
        at jetbrains.mps.smodel.WorkbenchModelAccess.runWriteAction(WorkbenchModelAccess.java:113)
        at jetbrains.mps.smodel.WorkbenchModelAccess$CommandRunnable.run(WorkbenchModelAccess.java:446)
        at com.intellij.openapi.command.impl.CoreCommandProcessor.executeCommand(CoreCommandProcessor.java:137)
        at com.intellij.openapi.command.impl.CoreCommandProcessor.executeCommand(CoreCommandProcessor.java:95)
        at com.intellij.openapi.command.impl.CoreCommandProcessor.executeCommand(CoreCommandProcessor.java:85)
        at jetbrains.mps.smodel.WorkbenchModelAccess.runWriteActionInCommand(WorkbenchModelAccess.java:311)
        at jetbrains.mps.smodel.WorkbenchModelAccess.executeCommand(WorkbenchModelAccess.java:307)
        at jetbrains.mps.project.ProjectModelAccess.executeCommand(ProjectModelAccess.java:43)
        at Simulatie.Swing.BadButtons$1.actionPerformed(BadButtons.java:16)
        at javax.swing.AbstractButton.fireActionPerformed(AbstractButton.java:2022)
        at javax.swing.AbstractButton$Handler.actionPerformed(AbstractButton.java:2348)
        at javax.swing.DefaultButtonModel.fireActionPerformed(DefaultButtonModel.java:402)
        at javax.swing.DefaultButtonModel.setPressed(DefaultButtonModel.java:259)
        at javax.swing.plaf.basic.BasicButtonListener.mouseReleased(BasicButtonListener.java:252)
        at java.awt.Component.processMouseEvent(Component.java:6533)
        at javax.swing.JComponent.processMouseEvent(JComponent.java:3324)
        at java.awt.Component.processEvent(Component.java:6298)
        at java.awt.Container.processEvent(Container.java:2236)
        at java.awt.Component.dispatchEventImpl(Component.java:4889)
        at java.awt.Container.dispatchEventImpl(Container.java:2294)
        at java.awt.Component.dispatchEvent(Component.java:4711)
        at java.awt.LightweightDispatcher.retargetMouseEvent(Container.java:4888)
        at java.awt.LightweightDispatcher.processMouseEvent(Container.java:4525)
        at java.awt.LightweightDispatcher.dispatchEvent(Container.java:4466)
        at java.awt.Container.dispatchEventImpl(Container.java:2280)
        at java.awt.Window.dispatchEventImpl(Window.java:2746)
        at java.awt.Component.dispatchEvent(Component.java:4711)
        at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:758)
        at java.awt.EventQueue.access$500(EventQueue.java:97)
        at java.awt.EventQueue$3.run(EventQueue.java:709)
        at java.awt.EventQueue$3.run(EventQueue.java:703)
        at java.security.AccessController.doPrivileged(Native Method)
        at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:80)
        at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:90)
        at java.awt.EventQueue$4.run(EventQueue.java:731)

 

0
Comment actions Permalink

So, are you passing "null" as the progress monitor? This would explain the null pointer exception ;)

0
Comment actions Permalink

Hi Rbert, I am not passing a null progress monitor, but instead I create a new empty ProgressMonitor when calling the check method as follows:

modelChecker.check(itemsToCheck, repo, issues, new ProgressMonitor() {
  public void start(@NotNull() String p0, int p1) {
    <no statements>
  }
  public void advance(int p0) {
    <no statements>
  }
  public void step(String p0) {
    <no statements>
  }
  public void done() {
    <no statements>
  }
  public boolean isCanceled() {
    return false;
  }
  public void cancel() {
    <no statements>
  }
  public ProgressMonitor subTask(int p0) {
    return null;
  }
  public ProgressMonitor subTask(int p0, SubProgressKind p1) {
    return null;
  }
})

 

0
Comment actions Permalink

Okay, but your implementation of subTask returns null.

The checkers you invoke take the progress monitor passed in and try to create sub tasks for their checks, so you must not return null there.

I should have mentioned this at the beginning, but if you opt for option 1 (the one you have tried so far), I think your checks must run in a backgroundable task . There is documentation on this here: https://confluence.jetbrains.com/display/MPSD20181/Progress+indicators

 

We have something along the lines of this:

public static void check(final MPSProject mpsProject, final list<model> allModels) { 
final CountDownLatch myLatch = new CountDownLatch(1);
final SearchResults<IssueKindReportItem> searchResults = new SearchResults();

// hide latest checker results
ModelCheckerTool.getInstance(ProjectHelper.toIdeaProject(mpsProject)).?getSelectedTab().?setVisible(false);

final Project openAPIProject = mpsProject.getProject();
final SRepository repo = mpsProject.getRepository();

ProgressManager.getInstance().run(new Task.Backgroundable(openAPIProject, "Checking ...", true) {
public void run(@NotNull() ProgressIndicator progressIndicator) {
//this is where we instantiate our "main" progress monitor
ProgressMonitor pm = new ProgressMonitorAdapter(progressIndicator);
pm.start("", allModels.size);
read action with repo {
foreach model in allModels {
ProgressMonitor pmSub = pm.subTask(1, SubProgressKind.DEFAULT);
// checkModel contains more or less the code from my original reply, where we call pmSub.start right before we initialize the ModelCheckerBuilder
// the "pmSub" we pass into "modelChecker.check(itemsToCheck, repo, issues, pmSub)" is another sub-progress monitor of this pmSub here
searchResults.addAll(CheckUtils.checkModel(mpsProject, model, pmSub));

if (pmSub.isCanceled()) {
pm.cancel();
break;
}
}
}
if (!pm.isCanceled()) {
pm.done();
}
myLatch.countDown();
}

@Override
public boolean shouldStartInBackground() {
false;
}
});

// this task is for showing the results in the model checking tool window
ProgressManager.getInstance().run(new Task.Backgroundable(openAPIProject, "Presenting results ...", true) {
public void run(@NotNull() ProgressIndicator progressIndicator) {
try {
myLatch.await();
execute in EDT with repo {
ModelCheckerViewer resultViewer = new ModelCheckerViewer(openAPIProject, false);
resultViewer.setSearchResults(searchResults);
ModelCheckerTool.getInstance(openAPIProject).showTabWithResults(resultViewer, "results", null);
}
} catch (Exception e) {
e.printStackTrace();
}
}
});

}

 

 

 

 

0
Comment actions Permalink

It might be worthwhile to see if the second option suits your needs better, especially if you want to check single nodes.

0
Comment actions Permalink

Hi Robert, I changed my code to return `this` instead of null in de subtask monitors,  and now my code works ok.

 

Thanks !

 

Jos

0

Please sign in to leave a comment.