Issues with unused local variables, fields and methods used inside lambdas (Java8; S1481; S1068; squid:UnusedPrivateMethod)

2,457 views
Skip to first unread message

kuja...@gmail.com

unread,
Jul 29, 2016, 7:50:51 AM7/29/16
to SonarQube
Hello together,

we are using SonarQube 5.6.1 and i have a case where i get 3 errors (S1481; S1068; squid:UnusedPrivateMethod) that are all invalid.

i have a "private static final String" a local Map and a private method. each of them triggers the relevant of the mentioned errors but all are used inside of lambdas.

here is a (reduced) copy of the code

// this field causes unused private field
private static final String ASSGIN_NEW_BRAND = "...";

private void reassignAccountBrands(Map<String, Brand> brandMap) {
// this local variable causes unused local variable
Map<Long, Brand> brandIds = brandMap.values().stream().collect(toMap(Brand::getId, Function.identity()));
jdbcTemplate.query(SELECT_ACCOUNTS, Account::new)
    .stream()
    .filter(a -> !brandIds.keySet().contains(a.getBrand())) // uses the local variable inside lambda...
    .peek(a -> a.replaceBrand(brandMap))
    .forEach(a -> jdbcTemplate.update(ASSGIN_NEW_BRAND, updateArgs(a))); // uses the field and the method inside lambda...

// more code
}

// this method causes unused private method
private Map<String, ?> updateArgs(Account a) {
// code
}

in another file i have another case of the unused method that is used inside a lambda


is this a bug or do i have to configure sonar to be more correct with these checks... maybe set the Java version somewhere to 8? 

José Antonio Olivan

unread,
Aug 2, 2016, 10:02:06 AM8/2/16
to SonarQube, kuja...@gmail.com
I'm suffering the same issue. Lots of false positives.In my case with SonarQube 5.6

Brian Sperlongano

unread,
Aug 2, 2016, 10:32:06 AM8/2/16
to SonarQube, kuja...@gmail.com
Are you using the latest Java plugin, version 4.0?  That was one of the recently fixed issues.

Michael Gumowski

unread,
Aug 2, 2016, 10:59:52 AM8/2/16
to Brian Sperlongano, SonarQube, kuja...@gmail.com
Hello all,

Thanks for pointing this out @Brian.

Could you please verify that you are using latest version 4.0 or the Sonar Java Analyzer?
Note that version 4.1 is about to be released. You may want to try with latest RC (4.1-RC2) as well.

Regards,

Michael GUMOWSKI | SonarSource
Software Developer @ Language Team
http://sonarsource.com

--
You received this message because you are subscribed to the Google Groups "SonarQube" group.
To unsubscribe from this group and stop receiving emails from it, send an email to sonarqube+...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/sonarqube/63648f2a-ad96-40d8-837a-3178c05cf183%40googlegroups.com.

For more options, visit https://groups.google.com/d/optout.

kuja...@gmail.com

unread,
Aug 3, 2016, 2:33:41 AM8/3/16
to SonarQube, zelon...@gmail.com, kuja...@gmail.com
Hello,

we are having this issue using 4.0. I'll see if we can give 4.1-RC2 a try.

kuja...@gmail.com

unread,
Aug 4, 2016, 2:43:01 AM8/4/16
to SonarQube, zelon...@gmail.com, kuja...@gmail.com
Hello Michael,

we updated our Java Plugin to 4.1 last night and i just let sonarqube analyze my project. unfortunately the errors are still present. all three.




Am Dienstag, 2. August 2016 16:59:52 UTC+2 schrieb Michael Gumowski:

Brian Sperlongano

unread,
Aug 4, 2016, 9:35:42 AM8/4/16
to SonarQube, zelon...@gmail.com, kuja...@gmail.com
I have also found this issue in 4.0 and 4.1.

I've been working to make a simple case that demonstrates the issue, however, it appears that the problem only happens under very specific conditions.  In most cases it seems to work correctly.

Brian Sperlongano

unread,
Aug 4, 2016, 10:17:22 AM8/4/16
to SonarQube, zelon...@gmail.com, kuja...@gmail.com
Ok, attached is a screen shot of the reproducer.  This is using the released Java plugin version 4.1.

The issue seems to be when a stream changes data types.  If you take out the map(...) call, the unused private warning goes away.

If you comment out the map(...) call and put the split inside the forEach, the warning goes away also.
unused_example.png

kuja...@gmail.com

unread,
Aug 4, 2016, 10:42:18 AM8/4/16
to SonarQube, zelon...@gmail.com, kuja...@gmail.com
Nice that you provided these information. But as one can see in my first post i do not have a map() call in my stream.

and in a second case i also have no map call, there it looks like this:

        runQuery(query, rs -> write(writer, extractor.extractData(rs)));

where the second arg to runQuery() is an org.springframework.jdbc.core.RowCallbackHandler
and the write() method is the falsely reported unused (private) method 

Michael Gumowski

unread,
Aug 5, 2016, 10:08:13 AM8/5/16
to Kay-Uwe Janssen, SonarQube, Brian Sperlongano
Hey guys,

Sorry for the delay answering you, and big thanks to all of you for the investigation you did and all the reproducers you provided! It's really appreciated!

We are currently experiencing issues with the semantic when dealing with the Stream API. As you can guess, deducing the type of expressions when chaining operations can sometime be pretty hard...

I created the following ticket which summarize all the issues that you reported: https://jira.sonarsource.com/browse/SONARJAVA-1802
I also created 3 other related tickets (SONARJAVA-1803SONARJAVA-1804SONARJAVA-1805), which covers FPS on the 3 related rules (Unused local variables, Unused private fields, Unused private methods).

Regards,

Michael GUMOWSKI | SonarSource
Software Developer @ Language Team
http://sonarsource.com

To unsubscribe from this group and stop receiving emails from it, send an email to sonarqube+unsubscribe@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/sonarqube/5edf7351-7dc8-41b5-9e9e-ebeb422f74e3%40googlegroups.com.

kuja...@gmail.com

unread,
Sep 8, 2016, 8:23:42 AM9/8/16
to SonarQube, kuja...@gmail.com, zelon...@gmail.com
Hello Michael,

we recently upgraded the sonar java plugin to 4.2. I just realized that there is still one case where i have a false positive with unused private method (squid:UnusedPrivateMethod).

private <D, L extends List<D>> Path queryToCsv(String type, String query,
       ResultSetExtractor<L> extractor) {
Path tempFile = createCsvTempFile(type);
try (BufferedWriter writer = Files.newBufferedWriter(tempFile)) {
runQuery(query, rs -> write(writer, extractor.extractData(rs))); // write(Writer, L) used here
writer.flush();
return tempFile;
} catch (IOException e) {
deleteFileIfExists(tempFile);
throw new TaskException("unable to write query result to csv", e);
}
}

private <D, L extends List<D>> void write(Writer writer, L data) { // unused method according to sonar
try {
for (D item : data) {
writer.write(item.toString());
writer.write("\r\n");
}
} catch (IOException e) {
throw new TaskException("unable to write line", e);
}
}


Regards,
Kay

Michael Gumowski

unread,
Sep 12, 2016, 11:17:30 AM9/12/16
to kuja...@gmail.com, SonarQube, zelon...@gmail.com
Hey Kay,

Thanks for the feedback and for providing more details about your remaining case. Generic methods, especially with dependency between type parameters seems to cause problems when trying to infer the type of the expression of the lambda expression. Consequently, we fail to resolve the method. I created the following ticket to handle the issue: https://jira.sonarsource.com/browse/SONARJAVA-1840

Regards,


For more options, visit https://groups.google.com/d/optout.
--

adere...@gmail.com

unread,
Sep 20, 2016, 10:49:55 AM9/20/16
to SonarQube, kuja...@gmail.com, zelon...@gmail.com
Hello,

We also still get these false-positives. SonarQube 6.0 with Java Plugin 4.2

"Remove this unused "pipedInputStream" local variable."
"Remove this unused "pipedOutputStream" local variable. "

in the following code snippet

 (StreamResource.StreamSource) () -> {
                        final PipedInputStream pipedInputStream = new PipedInputStream();
                        final PipedOutputStream pipedOutputStream;
                        try {
                            pipedOutputStream = new PipedOutputStream(pipedInputStream);
                        } catch (IOException e) {
                        throw new RuntimeException(e)
                        }
};

Cheers Alex

Michael Gumowski

unread,
Sep 21, 2016, 3:41:03 AM9/21/16
to adere...@gmail.com, SonarQube, kuja...@gmail.com, zelon...@gmail.com
Hello Alex,

Thanks for the feedback. About the code snippet your provide, would it be possible to also have the context in which you use this lambda expression? This is apparently a bug in the semantic of the java Analyzer and It would help to have the whole method or class containing it in order to pinpoint exactly where it fails. 

Note that I'm also guessing that the other thread you opened (about FP on exception being not preserved) has the same root cause. 

Cheers,

Michael


For more options, visit https://groups.google.com/d/optout.

Alexander Derenbach

unread,
Sep 21, 2016, 5:28:44 AM9/21/16
to SonarQube, adere...@gmail.com, kuja...@gmail.com, zelon...@gmail.com
Hello Michael,

Thx for your fast reply. I cannot post the complete code, as it is not open source, but I tried to give some more info around it. 
The lambda call is done inside a static method which requires a functional interface. The lambda expression is casted to this type (StreamResource.StreamSource).

The parts I removed and replaced with comments are just normal java code: assigning variables, if clauses etc. Nothing java8 special.
 
I looked up several issues with this false-positive and it seems at least in every case I looked at, there is a cast. 

import com.vaadin.server.StreamResource;

private void downloadByStreaming() {
               
/* do some stuff */
  DownloadHelper.download(
  (StreamResource.StreamSource) () -> {
                       final PipedInputStream pipedInputStream = new PipedInputStream();
                       final PipedOutputStream pipedOutputStream;
                       try {
                           pipedOutputStream = new PipedOutputStream(pipedInputStream);
                       } catch (IOException e) {
                        throw new RuntimeException(e)
                       }

                       /* some more stuff */
                        },
                        "filename.txt"
);
}



public static void download(StreamSource src, String fileName) {
/* do some stuff */
}


Thx for your help!

Cheers Alex

kuja...@gmail.com

unread,
Oct 26, 2016, 2:17:37 AM10/26/16
to SonarQube, kuja...@gmail.com, zelon...@gmail.com
Hello Michael,

we just updated to 4.2.1 but unfortunately the issue persists.

The case of my previous example is still detected as an unused method and to make it a bit worse... a new unused (via squid:UnusedPrivateMethod) has been falsely detected.

but this time it is not even used inside a lambda or method reference.


public Supplier<Map<ApportionmentTarget, BigDecimal>> costCenter(
        EtlBranch targetBranch, int bookingMonth) {
BiPredicate<DataKey, Set<EtlCostCenter>> shouldAdd = (key,
       src) -> src.contains(key.getCostCenter()) && targetBranch
           .equals(key.getPostApportionmentBranch());

return turnover(
   calculateTurnover(extractHelper::extractSourceCostCenter,
       shouldAdd, bookingMonth),
   calculateTurnover(extractHelper::extractSourceCostCenter,
       shouldAdd, bookingMonth));
}
// this method is deteced as unused but is used in the above method twice as parameter to turnover()
private <APPORT, SRC> Function<APPORT, BigDecimal> calculateTurnover(
        Function<APPORT, Set<SRC>> sourceExtractor,
        BiPredicate<DataKey, Set<SRC>> shouldAdd, int bookingMonth) {
return appOrTarget -> {
BigDecimal result = BigDecimal.ZERO;
Set<SRC> sources = sourceExtractor.apply(appOrTarget);
for (Entry<DataKey, DataValue> entry : profitData) {
if (entry.getKey().getBookingTime()
           .getMonth() == bookingMonth
               && shouldAdd.test(entry.getKey(), sources)) {
result = result
               .add(entry.getValue().getPreApportionment());
}
}
return result;
};
}
// here the turnover() signature in case it is related
private Supplier<Map<ApportionmentTarget, BigDecimal>> turnover(
        Function<Apportionment, BigDecimal> turnoverCalculator,
        Function<ApportionmentTarget, BigDecimal> targetTurnoverCalculator) {
// code cut
}


kuja...@gmail.com

unread,
Nov 9, 2016, 5:31:01 AM11/9/16
to SonarQube, kuja...@gmail.com, zelon...@gmail.com
*bump*

Just in case the message got overlooked

kuja...@gmail.com

unread,
Jan 2, 2017, 8:09:24 AM1/2/17
to SonarQube, kuja...@gmail.com, zelon...@gmail.com
Still having false unused method issues with 4.3.0.7717.

Michael Gumowski

unread,
Jan 16, 2017, 8:45:02 AM1/16/17
to kuja...@gmail.com, SonarQube, zelon...@gmail.com
Hello,

In order to reproduce the issue and identify once and for all the problem, can you please provide a self contained, reduced, code snippet reproducing the issue systematically? 
By self contained, we mean that all the dependencies should be provided and defined, except for default Java embedded classes. You can provide a file or a group of file.
By reduced, we mean that the code snippet should be as short and clean as possible, without code not related to the issue.

Now, a few additional questions:
  • Are you sure that you are providing the byte code of all the dependencies used by your classes? 
  • How are you analyzing your project?
Regards,

Michael


For more options, visit https://groups.google.com/d/optout.

Brian M. Sperlongano

unread,
Jan 16, 2017, 6:25:53 PM1/16/17
to Michael Gumowski, kuja...@gmail.com, SonarQube
Hi Michael,

Since I started this thread, I'll jump in.

My only remaining "unused private method" false positives are described by https://jira.sonarsource.com/browse/SONARJAVA-2033 as far as I can tell.

I see that it is marked as fixed in 4.5, if there is a nightly build, I'd be happy to test it out on my codebase.

Thanks for all your hard work.
Brian

To unsubscribe from this group and stop receiving emails from it, send an email to sonarqube+unsubscribe@googlegroups.com.

kuja...@gmail.com

unread,
Jan 27, 2017, 9:13:21 AM1/27/17
to SonarQube, michael....@sonarsource.com, kuja...@gmail.com
@Brian: actually I created this thread not you. :D

@Michael:

I created a repro case project on github: https://github.com/issuerepro/sonar-unused-private-methods

You can check it out and run with "mvnw clean package sonar:sonar -Dsonar.host.url=http://your.sonar.host"

Tested with:
- sonarqube: 5.6.4

Installed Plugins:
- checkstyle 2.4
- dependency-check 1.0.3
- findbugs 3.4.4
- git 1.2
- java 4.4.0.8066


I hope this helps to fix the issue.


Here is a screenshot of our results:


Michael Gumowski

unread,
Jan 30, 2017, 4:41:16 AM1/30/17
to kuja...@gmail.com, SonarQube
Hey Kay-Uwe,

Thanks a lot for the time you spent on providing a reproducer project, it helped me to corner the cases. I created the following ticket to handle the issues you encounter, which are all related to how we implemented type inference in our semantic engine: SONARJAVA-2084

@Brian: we will be starting RFF period (Request For Feedback) for version 4.5 of SonarJava in the incoming days, so you will be able to test it very soon.

Now, let's close this thread. If you encounter any new issue with the 'Unused private method' rule, please open a new thread.

Cheers,
Michael
Reply all
Reply to author
Forward
0 new messages