Following the sonar-custom-example-plugin I’ve created a simple sensor that analyzes “klingon” code (see below).
I have two files with the extension .klg that are correctly picked up by the sensor and have a simple issue reported on each of them when running a scan.
However, the project overview page says “The main branch has no lines of code”. If I place a java file in the same folder I’m greeted with the usual information.
I’m clearly missing something in the sensor. Adding some sort of measure to the files, perhaps? How would I make the sensor treat these files like other sensors do for other languages?
You have to provide the measure NCLOC_DATA for every file of your language. The value of this measure is a distribution (=map) with key = line number and value = 1 if line contains code.
To ease the creation of this measure, you can use FileLinesContextFactory (inject it into your Sensor constructor), then call
Trying to just save it for the first line as a test, it didn’t work at first. I had to manually add the measure NCLOC. The code now works and looks like this:
I’m not sure if it’s because of the new metric was necessary, or because only the latter works and the FileLinesContext is not being injected during the scanner execution. My constructor looks like this:
private final Checks<Object> checks;
private final FileLinesContextFactory contextFactory;
public KlingonSensor(CheckFactory checkFactory, FileLinesContextFactory fileLinesContextFactory) {
checks = checkFactory.create(KlingonRulesDefinition.REPOSITORY).addAnnotatedChecks((Iterable) CheckList.getKlingonClasses());
this.contextFactory = fileLinesContextFactory;
}
Is there some documentation I’m missing about NCLOC or core metrics in general?
That’s very possible that storing ncloc measure is also necessary (I though it would have been recomputed from ncloc_data, but I didn’t really checked). What is the SonarQube version you target BTW?
I don’t think we have a complete documentation listing all the measures that a new language should feed. Most of the time we simply suggest to people to have a look at one of our many open source analyzers, or simply look at the CoreMetrics class.
I’m targeting version 7.9. I got the idea of also feeding NCLOC from the SonarXML plugin. Looking at the open source analyzers is helpful most of the time, but it’s not immediately obvious what each thing does.
It is now my understanding that NCLOC_DATA keeps track of which lines contain code, and NCLOC keeps track of the total number of lines of code.
I am trying to solve the same issue with the project overview of a custom sensor.
I am puzzled by the code shown here, specifically how the FileLinesContextFactory gets instantiated. I can certainly add it as an argument to my Sensor’s constructor, but something has to provide a concrete implementation. Currently I’m creating my sensor inside my Plugin’s define method, so the ContextFactory would have to be created here. It’s an interface, and Eclipse is not finding any concrete implementations.
Perhaps I am missing something.
As far as I understand - and I haven’t touched this in a while, I’m afraid - the FileLinesContextFactory is instantiated by Sonar and injected into your custom sensor, all it needs is a constructor for a class that implements Sensor. Having a look at the usages for the constructor in my project, there’s only one in a test class with a mocked context factory.
You needn’t create a sensor in the Plugin’s define method, only add it to the context. This is my Plugin class:
public class KlingonPlugin implements Plugin {
@Override
public void define(Context context) {
context.addExtensions(Klingon.class,
KlingonQualityProfile.class,
Klingon.getProperties(),
KlingonSensor.class,
KlingonRulesDefinition.class,
KlingonLintIssuesLoaderSensor.class);
}
}
And this is my Sensor class:
public class KlingonSensor implements Sensor {
private final Checks<Object> checks;
private final FileLinesContextFactory contextFactory;
public KlingonSensor(CheckFactory checkFactory, FileLinesContextFactory fileLinesContextFactory) {
checks = checkFactory.create(KlingonRulesDefinition.REPOSITORY).addAnnotatedChecks((Iterable) CheckList.getKlingonClasses());
this.contextFactory = fileLinesContextFactory;
}
@Override
public void describe(SensorDescriptor descriptor) {
descriptor.name("Klingon sensor");
descriptor.onlyOnLanguage(Klingon.KEY);
}
@Override
public void execute(SensorContext context) {
//stuff
}
}
I remember having to add those preceding lines so Sonar would report new lines of code (the “LOC” in “NCLOC”) correctly. Both those setting had to be present, and they did two related, but separate, things. Again, sorry I’m being so vague, it’s been a while.
You will see the exact same implementation of the two metrics in the Sonar plugins for Java and XML, which I used as guidance.
There are various metrics you have to implement to correctly register the new lines of code in the report. Unfortunately there is no proper documentation for that (see Julien’s answer here).
Best thing you can do is to have a look at how the sensor is implemented in Sonarsource’s own plugins and study the code.