This Bugzilla instance is a read-only archive of historic NetBeans bug reports. To report a bug in NetBeans please follow the project's instructions for reporting issues.

Bug 211273 - No way to write a JavaFix replacing a sequence of statements
Summary: No way to write a JavaFix replacing a sequence of statements
Status: RESOLVED WONTFIX
Alias: None
Product: java
Classification: Unclassified
Component: Hints (show other bugs)
Version: 7.2
Hardware: PC Linux
: P3 normal (vote)
Assignee: Svata Dedic
URL:
Keywords:
Depends on:
Blocks: 207577
  Show dependency tree
 
Reported: 2012-04-16 16:48 UTC by Jesse Glick
Modified: 2016-07-07 07:18 UTC (History)
0 users

See Also:
Issue Type: DEFECT
Exception Reporter:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Jesse Glick 2012-04-16 16:48:41 UTC
Suppose you have a hint with something like

@TriggerPattern("Something $s = $decl; while ($s.cond()) {$rest$;}")

Now run it on a class with a method like

void m() {
  unrelatedCall();
  Something s = decl();
  while (s.cond()) {
    s.use();
  }
}

In JavaFix.performRewrite, ctx.path.leaf will be

{
  unrelatedCall();
  Something s = decl();
  while (s.cond()) {
    s.use();
  }
}

which is not very useful: you cannot safely call WorkingCopy.rewrite(leaf, ...something...) since you would first have to pick out unrelatedCall(). (Same for an unrelated set of statements after the while loop.)

HintContext.variables.get("$_") also produces the overly long block. Even if HintContext had the right information, it is not clear how to "send" it to the JavaFix; is that allowed to "keep" the HintContext, or will these TreePath's be "stale" by the time the fix is run? If it is OK, the hint template gives no indication of this.

BTW TreeMaker.removeBlockStatement(BlockTree, StatementTree) does nothing in this case:

Map<String,TreePath> vars = hctx.getVariables();
BlockTree block = (BlockTree) vars.get("$_").getLeaf();
for (StatementTree st : block.getStatements()) {
    System.out.println("found: " + st + " of kind: " + st.getKind());
}

shows the expected output, but

ctx.getWorkingCopy().getTreeMaker().removeBlockStatement(block, (StatementTree) vars.get("$s").getLeaf());

silently returns without any effect.

Obviously you could just look through the BlockTree for a WhileTree child, but there might be more than one - there is no apparent way to tell which one triggered the hint.

I tried prefixing the trigger with "$before$;" and suffixing with "$after$;" but this then makes it _not_ match when the real pattern is the only contents of the method's block. Also $before$ gets matched but $after$ does not.
Comment 1 Jesse Glick 2012-04-16 16:54:03 UTC
My bad, removeBlockStatement does work (just need to assign block to the return value). So this may be a viable workaround, assuming it is legitimate to use the HintContext inside performRewrite.
Comment 2 Jesse Glick 2012-04-16 17:52:13 UTC
Other apparent workaround is to use JavaFixUtilities.rewriteFix, which seems to behave naturally (like declarative fixes), assuming that you can indeed express the rewrite this way.
Comment 3 Jan Lahoda 2012-04-16 18:25:27 UTC
Yes, using JavaFixUtilities.rewriteFix is recommended whenever it is sufficient. It handles automatically a lot for the caller (e.g. resolves constant arithmetic expressions, generates parenthesis as appropriate, etc.), and is likely to handle even more in the future (multi-statement rewrites in CaseTrees, automatic beautification of boolean expressions, etc). In fact, the declarative fixes are based on JFU.rewriteFix, only pass some more information into it.

No, HintContext should not be kept outside the hint method.

I agree it is not easy to create a fix rewriting multiple statements in the middle of a BlockTree (or a CaseTree, which always complicates the matters). And will never be as easy as JFU.rF, even though it certainly can be made easier than it is today. It is not impossible to write such fix, though.

Depending on what exactly is the required outcome, easiest might be to use the TreePath for one of the statements as the "main" TreePath and start from it. In the given example, HintContext.getVariables().get("$s") should (I think at least) return the TreePath for the variable.

$before$; and $after$; are a known problem, and should be fixed.

Two other possible simplifications that come to mind are:
-allowing to pass more than one TreePath(Handle) to JavaFix constructor
-adding support for HintContext.getMultiVariables().get("$_"), which could return the TPs for the found statements
Comment 4 Jesse Glick 2012-04-16 19:07:13 UTC
rewriteFix actually does not work well in this case because any formatting & comments inside $rest$ is lost.
Comment 5 Jan Lahoda 2012-04-19 08:18:38 UTC
Making the outcomes of the declarative fixes more stable:
http://hg.netbeans.org/main-silver/rev/8f439a91333f
Fixing the $before$;/$after$; problem:
http://hg.netbeans.org/main-silver/rev/f720e6224e3c
Comment 6 Quality Engineering 2012-04-19 10:00:30 UTC
Integrated into 'main-golden', will be available in build *201204190400* on http://bits.netbeans.org/dev/nightly/ (upload may still be in progress)
Changeset: http://hg.netbeans.org/main-golden/rev/8f439a91333f
User: Jan Lahoda <jlahoda@netbeans.org>
Log: #211273: do not rewrite existing original trees. Ensures that the outcomes are more stable.
Comment 7 Quality Engineering 2012-04-20 10:13:17 UTC
Integrated into 'main-golden', will be available in build *201204200400* on http://bits.netbeans.org/dev/nightly/ (upload may still be in progress)
Changeset: http://hg.netbeans.org/main-golden/rev/5a7cab463695
User: Jan Lahoda <jlahoda@netbeans.org>
Log: #211273: a forgotten test case.
Comment 8 Martin Balin 2016-07-07 07:18:34 UTC
This old bug may not be relevant anymore. If you can still reproduce it in 8.2 development builds please reopen this issue.

Thanks for your cooperation,
NetBeans IDE 8.2 Release Boss