sonarqube


How can I ensure that the right bytecode is available to my custom sonar plugin rule, so I don't get !unknown! for every type?


I've been attempting to write a custom rules plugin for Sonarqube ~5.4, and while I've gotten a few rules implemented and working, the ones that rely on types outside the standard libraries rely on various kinds of acrobatic string matching.
I'm using the sonar-packaging-maven-plugin to do the packaging:
<plugin>
<groupId>org.sonarsource.sonar-packaging-maven-plugin</groupId>
<artifactId>sonar-packaging-maven-plugin</artifactId>
<version>1.16</version>
<configuration>
<pluginClass>${project.groupId}.sonar.BravuraRulesPlugin</pluginClass>
<pluginKey>SonarPluginBravura</pluginKey>
<skipDependenciesPackaging>false</skipDependenciesPackaging>
<basePlugin>java</basePlugin>
</configuration>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>sonar-plugin</goal>
</goals>
</execution>
</executions>
</plugin>
And am running the various checks using the following helper extension (kotlin):
fun <T : JavaFileScanner> T.verify() {
val workDir = System.getProperty("user.dir");
val folder = Paths.get(workDir, "src/test/samples", this.javaClass.simpleName);
Files.list(folder).forEach { sample ->
try {
if (sample.toString().endsWith(".clean.java")) {
JavaCheckVerifier.verifyNoIssue(sample.toString(), this);
} else {
JavaCheckVerifier.verify(sample.toString(), this);
}
} catch (error: Exception) {
throw VerificationFailedException(sample, error);
}
}
};
class VerificationFailedException(path: Path, error: Exception)
: Exception("Failed to verify $path.", error);
I create an IssuableSubscriptionVisitor subclass for the rule, and visit Tree.Kind.METHOD_INVOCATION, looking for uses of a static MAX, MIN, ASC, or DESC sql builder method being passed an AutoLongColumn. This is to stop the identifier field being used for ordering purposes.
Unfortunately, even though I have the requisite library on the maven 'test' classpath, when I try and get any of the types, they just show as !unknown!.
override fun visitNode(tree: Tree) {
if (tree !is MethodInvocationTree) {
return;
}
val methodSelect = tree.methodSelect();
if (methodSelect !is IdentifierTree || methodSelect.name() !in setOf("MAX", "MIN", "ASC", "DESC")) {
return;
}
val firstArg = statement.arguments().first();
if (firstArg !is MethodInvocationTree) {
return;
}
val firstArgSelect = firstArg.methodSelect();
if (firstArgSelect !is MemberSelectExpressionTree) {
return;
}
if (firstArgSelect.type is UnknownType) {
throw TableFlipException("(ノಥ益ಥ)ノ ┻━┻");
}
// It never gets here.
}
I'm sure I'm missing some vital piece of the puzzle, and I'd appreciate if someone can tell me where I'm going wrong.
EDIT: I'm using org.sonarsource.java:sonar-java-plugin:3.14 for the analyser, and while I can't release all the code for the analysis target (commercial IP and all that), here's something structurally identical to the key part:
import static com.library.UtilClass.MAX;
...
query.SELECT(biggestId = MAX(address._id())) // Noncompliant
.FROM(address)
.WHERE(address.user_id().EQ(userId)
.AND(address.type_id().EQ(typeId)));
...
The type of address.id() is an com.library.Identifier that wraps a long. I'd like to be able to visit all the method invocations, check if they match com.library.UtilCLass.MAX, and if so, make sure that the first parameter isn't a com.library.Identifier. Without the type information, I have to do a regex match on _id method references, which is prone to potentially missing things.
So, turns out that the way to get the types available is by using maven (or whatever tool you're using) to copy the needed jars into a directory, then turn the lot into a list of files, and pass that to the test verifier.
For example, lets pretend we're trying to find usages of joda-time:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>2.10</version>
<executions>
<execution>
<id>copy-libs</id>
<phase>generate-test-resources</phase>
<goals>
<goal>copy</goal>
</goals>
<configuration>
<artifactItems>
<artifactItem>
<groupId>joda-time</groupId>
<artifactId>joda-time</artifactId>
<version>2.9.4</version>
</artifactItem>
</artifactItems>
</configuration>
</execution>
<executions>
</plugin>
This execution will put the joda-time jar into the target/dependency directory. Next, you make sure to enumerate the jars in that directory, and add them to your test verification (we're assuming you named your verifier 'JodaCheck'):
// Not at all necessary, but it makes the code later on a lot easier to read.
fun <T> Stream<T>.toList(): List<T> = this.collect({
mutableListOf()
}, { list, item ->
list.add(item)
}, { list, otherList ->
list.addAll(otherList)
})
...
val workDir = System.getProperty("user.dir")
val sampleFile = Paths.get(workDir, "src/test/samples/JodaSample.java").toString()
val dependencies = Files.list(Paths.get(workDir, "target/dependency"))
.map { it.toFile() }.toList()
JavaCheckVerifier.verify(sampleFile, JodaChecker(), dependencies)
Once you've done that, debugging through the tests will show that the joda-time classes are available during analysis.

Related Links

getting error while clicking on profiles sonarQube
Running Sonar from command line without a SonarQube server
SonarQube: include files outside of the project into analysis
SonarQube Java 3.9 - AnalysisException
java plugin 3.9 false positive - always validates to true (squid:S2583)
Anyone use SonarCube with ObjectScript
SonarQube community edition licensing
Replacement of sonar-core.jar
Is SonarQube analysis incremental or?
Add a sonar rule to forbid use of URL GET parameter
Sonar Runner Behind a Proxy
Are the findbugs rules that come with sonarqube findbugs plugin same as the actual findbugs rules
How to handle certain SonarQube wrongly recognize rules?
Sonar quality profile in command line cannot be replaced by a project profile
Recover from sonarrunner leaving DB in inconsistent state
define perforce plugin in sonarqube

Categories

HOME
sonarqube
notepad++
porting
delphi-7
prism
telegram
yahoo-finance
camera
requirements
knitr
nuget
babeljs
google-cloud-datalab
crystal-reports-2013
vert.x
flume
bing-maps
spin
g++
drop-down-menu
heap
project-intu
x-cart
selectize.js
do-while
google-picker
pyramid
foreign-keys
digital-signature
production
sencha-touch
systemtime
object-storage
tosca
amazon-quicksight
mat
ceylon
realm-mobile-platform
corenlp-server
event-flow
hard-drive
login-script
openwhisk
hibernate-search
installscript
python-import
pdw-file-browser
numpy-broadcasting
openerp-7
sql-server-ce
dm-script
timing
magento-1.9.3
apriori
datacachefactory
flask-login
opennms
serde
reportservice2010
dbcontext
dtsearch
tinymce-3
mongotemplate
qtranslate
oracleclient
juice-ui
rmongo
slackware
microstation
ng-grid
dup
lean
android-wake-lock
kango-framework
hadoop-partitioning
qbxml
tfs-workitem
fuelcms
sha512
cwrsync
git-ftp
jquery-forms-plugin
fits
cross-join
iiop
primitive-types
iso-prolog
kissfft
ora-00904
functional-java
ios8-extension
amslidemenu
visual-studio-express
eclipse-kepler
embedded-fonts
script#
process-explorer
time.h
epiceditor
actiondispatch
android-icons
android-sdk-2.3
patricia-trie
jquery-blockui
oracle-enterprise-linux
koken
entity-attribute-value
listactivity
rmdir
dataform
appledoc
commerceserver2007
timertask
uideviceorientation
dot-emacs
lxr
wcf-instancing
wcf-proxy

Resources

Encrypt Message