How to get the value of the arguments of the sonar tree - java

I'm writing a custom rule for SonarQube for java, I want to check if the value of an argument is qualified. For example, I want to know if the String fit the specific pattern. I can only test if the argument is a String, but I can not get the exact value. Does the API allows me to do so?
For example, for the code below
log.error("errorID:210134 It's an error");
Can I get the argument and test if the string contains errorID?
Besides, can I get what variable did the method invocation?
For example, for the code below
log.error("errorID:210134 It's an error");
How can I know that log is an Object of the class Logger?

The following should do the trick:
When looking at the argument of the method invocation, check if its kind is a STRING_LITERAL, then cast the argument into a LiteralTree. From there, you will be able to access its value, as a String (Note that it will contain the double quotation marks).
To check if the invocation was done on a variable, get the methodSelect() expression tree from the method invocation. If its kind is a MEMBER_SELECT, cast it to MemberSelectExpressionTree. From there, check if the kind of the expression() is an IDENTIFIER. If it's the case, then you will be able to get the IdentifierTree and its associated symbol. You will then be able to say if the symbol calling the method is a variable or not, check its type, etc.

Related

MapBox - Define PropertyFactory.iconImage using expressions

I am trying to define the value for the method PropertyFactory.iconImage for my layer object. The return value PropertyValue<String> should use a certain field inside the Feature to define it's value.
The result could look something like that:
PropertyFactory.iconImage(Expression.step(Expression.get("myfield"),"mydefaultValue", Expression.Stop.stop("case1", "valueForCase1"), Expression.Stop.stop("case2", "valueForCase2"));
Unfortunately I was not able to find a similar solution so far.
The following expression solved my problem:
SymbolLayer("asset-layer", "assetMapDataSource").withProperties(
PropertyFactory.iconImage(Expression.match(
Expression.get("asset_type"), Expression.literal("bbq_default"),
Expression.stop("bridge", Expression.literal("bridge_default")))))
Edit:
Some more information why I used the method in my example:
PropertyFactory.iconImage expects a string which points to a certain bitmap that you have saved before via MapBoxMap.addImage(...).
Expression.match is used to "match" a certain String based on the given stop and default cases.
Expression.get is used to access a certain field inside your feature property. In this case the field "asset_type" provides a certain type that I can match against.
The default case of the Expression.match and each Expression.stop are using the Expression.literal. This method is used to tell the underlying expression system that your value is from type x (in that case String). Take a look at the Expression.literal methods to get an idea of that.
Each Expression.stop is used to symbolize that the Expression.match is trying to "match" the given value from the first parameter of Expression.stop against the given Expression.get value. If Expression.get and that method value are the same, the 2nd value of the Expression.stop is used which provides the actual value for the Expression.iconImage. If the underlying expression system wasn't able to find a "matching" stop for the given Expression.get value, the system will use the default value (in that case Expression.literal("bbq_default")).

TinyTextImpl insted of String xslt

I have the below XML,
<outer.element>
<bold>
<csc>CSCTEXT</csc>
REST OF THE TEXT
</bold>
</outer.element>,
i try to retrieve the text inside the <outer.element> element tag and sending it to a java method. i get the below exception,
XPathException: A sequence of more than one item is not allowed as the second argument of class:method() ("CSCTEXT", "REST OF THE TEXT").
if i use an array in the java method signature i get the below exception,
"Cannot convert value class net.sf.saxon.tinytree.TinyTextImpl of type text() to class java.lang.String"
how do i send a single concatenated value (class:method() ("CSCTEXT REST OF THE TEXT")) to the java method.?
Thank you in advance.
The first error:
XPathException: A sequence of more than one item is not allowed as the second argument of class:method() ("CSCTEXT", "REST OF THE TEXT").
means that you're calling your Java method with a sequence of values when it is only expecting one.
Using collection classes in the signature of your Java method will tend to mean that the individual items don't get converted, hence the second error "Cannot convert...".
One solution to that is to do the conversion yourself in the function call (for example, by calling the data() function). Or do it in the Java method (call the getStringValue() method on the supplied items).
If I am writing extension functions in Java specifically to be called from XPath/XSLT, then I will nowadays uses Saxon-specific classes in the method signature, for example ZeroOrMore<StringValue>. Saxon will then use exactly the same calling conventions as it uses for native XSLT/XPath functions (for example, implicit atomization) and your called code can do any further conversion needed itself.

What is the best way to check "method call" match format using checkstyle?

I have a group of methods that belong a single class that should contain at-least 2 parameters. The first one should be of type "literal" string (e.g. instance.do("literal_string", obj) - should be specified just right in the method call line itself). As next first parameter should also match a given regex pattern. The second argument can have any value (Object).
Additionally first parameter should be unique across whole project (this part is not really that important to consider).
Are there any possibilities to implement a check for conditions I've listed above? (Perhaps with checkstyle? Or custom Java annotations?)
Upd. Such a check should be preferably executed during dev-time (e.g. hinting a yellow light bulb in eclipse).
Do you mean something like:
if(nameOfStringVar.matches("regex")){
throw new java.lang.Error("First arg did not match the regex");
}
Objects.requireNonNull(nameOfSecondVariable);
?

Finding and replacing a value in HashMap?

I wrote a HashMap with the key as a String and the value as a LinkedList of Strings.
I want to write a method that consumes the key which is a string and value. Then I want find the key in the HashMap that match the given key then add the given String to the List of the Strings.
**thank guys but there is another error.
in this line "Likes.put(s,Likes.get(s).add(fav)); ." it says :
Error: no suitable method found for put(java.lang.String,boolean)
method java.util.HashMap.put(java.lang.String,java.util.LinkedList<java.lang.String>) is not applicable
(actual argument boolean cannot be converted to java.util.LinkedList<java.lang.String> by method invocation conversion)
method java.util.AbstractMap.put(java.lang.String,java.util.LinkedList<java.lang.String>) is not applicable
(actual argument boolean cannot be converted to java.util.LinkedList<java.lang.String> by method invocation conversion)
I can't tell why it says "the actual argument is Boolean"! I want to insert a LinkedList no a boolean
class Recomnder {
Recomnder(){
Likes.put("tom",new LinkedList() );
Recomnder.addLikes("tom","movie tovi");
}
HashMap<String,LinkedList<String>> Likes = new HashMap<String,LinkedList<String>>();
void addLikes (String name, String fav){
for (String s : Likes.keySet()) {
if (s.equals(name))
Likes.put(s,Likes.get(s).add(fav));
}
}
}
The problem is in this statement:
Recomnder.addLikes("tom","movie tovi");
That way you are telling the compiler that you want to access addLikes as a static method. However it is not defined as a static method. You can only call addLikes on an instance of Recomnder. So if you change it to:
addLikes("tom","movie tovi");
it should work.
btw. try adhering to Java naming conventions. Get used to always start instance variable names with a small case letter (e.g. likes instead of Likes). That way you spot such a mistake much easier.
Instance methods need to be called from an instance. Your addLikes method is an instance method (it doesn't have the modifier static). You need to create an instance of the class before you can call the method on it.
Apart from changing your method to static. Change the following statement.
Before
Likes.put(s,Likes.get(s).add(fav));
After
Likes.get(s).add(fav);
In the above code, Likes.get(s).add(fav) return boolean and this return value is being added to the Map. Hence the compiler giving the error.
Just adding the String to the Likes.get(s) will do the trick as java works on references. This will work as expected.

Removing compiler's warning from a method call, advise needed

As part of my Utils class, i have both
public static boolean isStringEmptyOrNull(String... s) {
When testing for a null condition
assertTrue(Utils.isStringEmptyOrNull(null));
I get "The argument of type null should explicitly be cast to String[] for the invocation of the varargs method isStringEmptyOrNull(String...) from type Utils. It could alternatively be cast to String for a varargs invocation" warning.
I'd rather not case anything though. This test is designed to simulate a condition where argument passed to the method is a null.
Is there a way to remove this warning without changing the signature of the method?
You should probably test both of these cases:
assertTrue(Utils.isStringEmptyOrNull(new String[] { null }));
assertTrue(Utils.isStringEmptyOrNull((String[]) null));
... although it's not clear to me why a method which sounds like it should only take a single string is taking an array of strings in the first place, to be honest.
(Is it obvious to you which of those invocations you meant without the cast? It isn't obvious to me... I'd have to look it up to check.)
If you are trying to mimic the way a client of your library function would call your code, you should take advantage of the fact that they will not call this particular method with the literal "null" (what would be the point?)
Instead, they would pass in some variable or expression. Since that's the case, you can do something like this and avoid casting:
String nullString = null;
assertTrue(Utils.isStringEmptyOrNull(nullString));
You could specifically tell the compiler to ignore the warning using #SuppressWarnings("all").
Well that warning's there for a reason: when you call your method with null argument, since null is all and any type in Java (including Array), the compiler effectively will not know if you're calling the var-args method with an array or a non-array object (each of which is treated differentlly when var-args arguments are used). What you can do is annotate the method with SuppressWarnings("All") and then test for null before doing anything with the argument(s)
Change your test like so:
String nullString = null;
assertTrue(Utils.isStringEmptyOrNull(nullString));
Rather curious why you use a vararg method for this in the first place though...

Categories

Resources