netbeans icon indicating copy to clipboard operation
netbeans copied to clipboard

AssertionError unexpected type: none in TreeMaker when using hint to create private method

Open jjazzboss opened this issue 5 months ago • 5 comments

Apache NetBeans version

Apache NetBeans 26

What happened

Was coding a java file. File is compilable. Typing a call to a new unknown method. Hint appears to propose to create the method locally, OK => exception below (method is not created)

java.lang.AssertionError: unexpected type: none
	at com.sun.tools.javac.tree.TreeMaker.Type(TreeMaker.java:888)
	at org.netbeans.modules.java.source.builder.TreeFactory.Type(TreeFactory.java:895)
	at org.netbeans.api.java.source.TreeMaker.Type(TreeMaker.java:1244)
	at org.netbeans.modules.java.hints.errors.CreateMethodFix$1.run(CreateMethodFix.java:243)
	at org.netbeans.modules.java.hints.errors.CreateMethodFix$1.run(CreateMethodFix.java:166)
	at org.netbeans.api.java.source.JavaSource$1.run(JavaSource.java:671)
	at org.netbeans.api.java.source.JavaSource$1.run(JavaSource.java:661)
	at org.netbeans.api.java.source.JavaSource$MultiTask.run(JavaSource.java:504)
	at org.netbeans.modules.parsing.impl.TaskProcessor.callUserTask(TaskProcessor.java:586)
	at org.netbeans.modules.parsing.api.ParserManager$UserTaskAction.run(ParserManager.java:197)
	at org.netbeans.modules.parsing.api.ParserManager$UserTaskAction.run(ParserManager.java:180)
	at org.netbeans.modules.parsing.impl.TaskProcessor$2.call(TaskProcessor.java:181)
	at org.netbeans.modules.parsing.impl.TaskProcessor$2.call(TaskProcessor.java:178)
	at org.netbeans.modules.masterfs.filebasedfs.utils.FileChangedManager.priorityIO(FileChangedManager.java:153)
	at org.netbeans.modules.masterfs.providers.ProvidedExtensions.priorityIO(ProvidedExtensions.java:335)
	at org.netbeans.modules.parsing.nb.DataObjectEnvFactory.runPriorityIO(DataObjectEnvFactory.java:118)
	at org.netbeans.modules.parsing.impl.Utilities.runPriorityIO(Utilities.java:67)
	at org.netbeans.modules.parsing.impl.TaskProcessor.runUserTask(TaskProcessor.java:178)
	at org.netbeans.modules.parsing.api.ParserManager.parse(ParserManager.java:83)
	at org.netbeans.api.java.source.JavaSource.runUserActionTaskImpl(JavaSource.java:454)
	at org.netbeans.api.java.source.JavaSource.runUserActionTask(JavaSource.java:425)
	at org.netbeans.api.java.source.JavaSource.runModificationTask(JavaSource.java:680)
	at org.netbeans.modules.java.hints.errors.CreateMethodFix.getModificationResult(CreateMethodFix.java:166)
	at org.netbeans.modules.java.hints.errors.CreateMethodFix.implement(CreateMethodFix.java:154)
	at org.netbeans.modules.editor.hints.HintsUI$1.run(HintsUI.java:810)
	at org.openide.util.RequestProcessor$Task.run(RequestProcessor.java:1403)
	at org.netbeans.modules.openide.util.GlobalLookup.execute(GlobalLookup.java:45)
	at org.openide.util.lookup.Lookups.executeWith(Lookups.java:287)
[catch] at org.openide.util.RequestProcessor$Processor.run(RequestProcessor.java:2018)

Language / Project Type / NetBeans Component

Netbeans RCP platform app

How to reproduce

See call to getAllSizeWbpsas(store, bar);, select hint to create method. Note that file was compilable except for this new method.

      /*
       * 
       *   DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
       *  
       *   Copyright @2019 Jerome Lelasseux. All rights reserved.
       * 
       *   This file is part of the JJazzLab software.
       *    
       *   JJazzLab is free software: you can redistribute it and/or modify
       *   it under the terms of the Lesser GNU General Public License (LGPLv3) 
       *   as published by the Free Software Foundation, either version 3 of the License, 
       *   or (at your option) any later version.
       * 
       *   JJazzLab is distributed in the hope that it will be useful,
       *   but WITHOUT ANY WARRANTY; without even the implied warranty of
       *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
       *   GNU Lesser General Public License for more details.
       *  
       *   You should have received a copy of the GNU Lesser General Public License
       *   along with JJazzLab.  If not, see <https://www.gnu.org/licenses/>
       *  
       *   Contributor(s): 
       * 
       */
      package org.jjazz.jjswing.walkingbass;
      
      import com.google.common.base.Preconditions;
      import java.util.List;
      import java.util.function.Predicate;
      import java.util.logging.Level;
      import java.util.logging.Logger;
      
      /**
       * Tile in bar order the most compatible WbpSourceAdaptation whose WbpSource was never used or was used the furthest from current bar.
       * <p>
       */
      public class TilerMaxDistance implements Tiler
      {
      
          private final Predicate<Score> minScoreTester;
          private static final Logger LOGGER = Logger.getLogger(TilerMaxDistance.class.getSimpleName());
      
          /**
           *
           * @param minScoreTester Ignore WbpSourceAdapatations which do not satisfy this predicate
           */
          public TilerMaxDistance(Predicate<Score> minScoreTester)
          {
              this.minScoreTester = minScoreTester;
          }
      
      
          @Override
          public void tile(WbpTiling tiling, WbpsaStore store)
          {
              LOGGER.log(Level.FINE, "tile() --");
      
              // LOGGER.log(Level.FINE, "tile() store=\n{0}", store.toDebugString(true));
      
              var nonTiledBars = tiling.getNonTiledBars();
              var itBar = nonTiledBars.iterator();
      
              while (itBar.hasNext())
              {
                  int bar = itBar.next();
                  var wbpsas = getAllSizeWbpsas(store, bar);      // EXCEPTION here when selecting hint to create method
                  if (wbpsas.isEmpty())
                  {
                      continue;
                  }
      
                  var wbpsa = select(tiling, wbpsas);
                  if (wbpsa != null)
                  {
                      tiling.add(wbpsa);
      
                      // Advance
                      int wbpsaSize = wbpsa.getBarRange().size();
                      while (wbpsaSize-- > 1)
                      {
                          itBar.next();
                      }
                  }
              }
      
          }
      
          // ====================================================================================================================
          // Private methods
          // ====================================================================================================================
          /**
           * Select the first WbpSourceAdaptation in wbpsas whose WbpSource was never used, or was used at the furthest bar.
           *
           * @param tiling
           * @param wbpsas Can not be empty. All WbpSourceAdaptation must start at the same bar.
           * @return Can be null
           */
          private WbpSourceAdaptation select(WbpTiling tiling, List<WbpSourceAdaptation> wbpsas)
          {
              Preconditions.checkArgument(!wbpsas.isEmpty());
      
              WbpSourceAdaptation res = null;
              int maxMinDistance = -1;
              int wbpsaBar = wbpsas.get(0).getBarRange().from;
      
              for (var wbpsa : wbpsas)
              {
                  var usageBars = tiling.getStartBarIndexes(wbpsa.getWbpSource(), true);  // Use false for less possible redundancies
      
                  if (usageBars.isEmpty())
                  {
                      res = wbpsa;    // not used before, use it now
                      break;
                  }
      
                  // Used, find the largest min distance
                  int minDistance = usageBars.stream()
                          .mapToInt(bar -> Math.abs(bar - wbpsaBar))
                          .min()
                          .orElseThrow();
                  if (minDistance > maxMinDistance)
                  {
                      maxMinDistance = minDistance;
                      res = wbpsa;
                  } else if (minDistance == maxMinDistance)
                  {
                      // Randomly select to avoid repetitions
                      var oldRes = res;
                      res = Math.random() > 0.5 ? oldRes : wbpsa;
                  } else
                  {
                      assert res != null;
                  }
              }
      
              return res;
          }
      
      }

Did this work correctly in an earlier version?

No / Don't know

Operating System

Win 11

JDK

Adoption JDK 23

Apache NetBeans packaging

Apache NetBeans binary zip

Anything else

No response

Are you willing to submit a pull request?

No

jjazzboss avatar Jun 16 '25 19:06 jjazzboss

With the information given, I can reproduce the error. The problem may lie in the fact that the user uses var instead of a proper type. This means that the hints engine has no clue on what expected return type of the getAllSizeWBpsas(store, bar); should be. Hence, it thinks the return type is unspecified (none), nor void.

The user can prevent the issue by supplying a type.

For NetBeans hints: If the return type is not known, maybe first hint to provide a type, then hint to create method. Note that NetBeans (or the compiler) cannot infer the expected type because the method does not yet exist.

Tested with NetBeans 26 on Java 21 on Ubuntu Linux 24.04

homberghp avatar Jun 18 '25 08:06 homberghp

Minimal example showing the 'problem'

public class UnknownType {


    public static void main(String[] args) {
        new UnknownType().method(args);
    }
    void method(String[] args){

        var whoKnows = whoKnows(args);
    }

}

Select the line method whoKnows, the select hint create method 'whoKnows(String[] args); This will produce an error bulb in the status line.

homberghp avatar Jun 18 '25 19:06 homberghp

@jlahoda In javahints/org.netbeans.modules.java.hints.errors.CreateMethodFix one could test for the return type to be none and change the hint message appropriately or otherwise higher up in the call tree, produce a different hint.

Or maybe add an extra hint (if it does not already exist) to supply an explicit type, asking the user for the type.

https://github.com/apache/netbeans/blob/256edf4e977f03a02c7c8b78a3db8311779ac911/java/java.hints/src/org/netbeans/modules/java/hints/errors/CreateMethodFix.java#L115-L121

In line line 116-120 tests for return type to be null (for void methods and constructors?) or not null exist. A test for returnType == TypeKind.NONE can prevent the error, but may not provide the best user experience.

One could consider this case to be a user error to be flagged as such, avoiding further changes in the hint system. The error could say something like var types and unknown methods cannot be combined. but I have no idea if a hint could be turned into such an error.

With some guidance, I would be willing to work on a solution.

homberghp avatar Jun 18 '25 19:06 homberghp

Silly me.

Maybe the simple solution is just to not propose the hint in that case.

jjazzboss avatar Jun 18 '25 20:06 jjazzboss

In that case, the patch would be simple. Add a guard in the process that proposes the hints. I will give it a try.

Just now (2025-06-19 23:07) , I submitted a PR. Let us see what the experts say.

homberghp avatar Jun 19 '25 14:06 homberghp