Find all method calls with a specific parameter type with IntelliJ - intellij-idea

I have this code base which is rather big ( +/- 500k lines). I'm looking in it to find all the method calls that use a single parameter and that parameter is a specific type.
This means, I want to be able to find method calls like the following:
public class Foo { }
public class Bar { }
public class Doer{
public void doSomethingFoo(Foo foo) { }
public void doSomethingObject(Object object) { }
}
public class Usage {
Doer doer = new Doer();
public doSomething() {
Foo anObject = new Foo();
Bar bar = new Bar();
doer.doSomethingFoo(anObject);
doer.doSomethingObject(anObject);
doer.doSomethingObject(bar);
}
}
Since both doer.doSomethingFoo(anObject) and doer.doSomethingObject(anObject) are called, both those statements should be returned by the search. Similarly, doer.doSomethingObject(bar) is not returned. Of course, I don't know that doer exists.
I'm trying to use the Structural Search of IntelliJ to do so. I've used the following template $Instance$.$Method$($Parameter$), with the following parameters:
$Instance$ -> Text/regexp = .*
$Method$ -> Text/regexp = .*
$Parameter$ -> Text/regexp = Foo
Minimum count = 1 // Minimum one Foo parameter
Maximum count = 1 // Maximum one Foo parameter
This returns everything that has a parameter named foo (case-insensitive, apparently). So I'm probably doing something wrong here. But what? How can I get all calls to any method where the only param is of type Foo?

You are almost there. All you need to do now is set the Expression type (regexp) of $Parameter$ to Foo and leave Text/regexp blank. Additionally you may want to enable the Apply constraint within type hierarchy checkbox, to find subclasses of Foo too.
Note that you can leave the Text/regexp of all variables blank. This is equivalent to .*.

Related

How to figure out which methods IDynamicMemberReferenceOperation refers to?

I have the following function in my OperationWalker:
public override void VisitDynamicInvocation(IDynamicInvocationOperation operation)
{
var memberReferenceOp = (IDynamicMemberReferenceOperation)operation.Operation;
switch (memberReferenceOp.Instance.Type)
{
case INamedTypeSymbol type:
{
var memberName = memberReferenceOp.MemberName;
var members = type.GetMembers(memberName);
if (members.Length > 1)
{
// WHAT DO I DO HERE ???
}
else
{
Result.Add((IMethodSymbol)members[0]);
}
break;
}
case IDynamicTypeSymbol dynamicType:
Unresolved.Add((operation.Syntax, memberReferenceOp.MemberName));
break;
}
}
I am clueless when a method on a normal type (non dynamic) is called with a dynamic parameter and there is a choice of target methods with the same name. E.g.:
class A
{
public void Get(int i){}
public void Get(string s){}
public void Get(object o){}
public void Get(double s, int precision){}
}
...
dynamic x = ...;
A a;
a.Get(x)
In this case any of the first 3 A.Get methods may be called, depending on the actual type of x. But not the fourth method.
Is there a way in Roslyn to get this information? Specifically in this example, I would like to get the symbols for first 3 Get methods.
The logic is non trivial, because one needs to take into account:
Default parameters, so just counting the arguments may not be enough
Type conversions
Visibility Scope
Number of arguments
Parameters may be passed using the named syntax in arbitrary order
Combining it all together we get non trivial logic. Is there anything in the SemanticModel or anywhere else to help get the answer?
I figured it out and it is straightforward - SemanticModel.GetSymbolInfo. When there is exact match its Symbol property returns it. When there are multiple candidates, as may be the case when one of the passed arguments is dynamic, then the property CandidateSymbols holds all the options.
I have not tested it with extension methods, so it is possible there is a gap there.

Implementing interfaces in Kotlin

could anyone explain to me the syntax of this interface implementation?
Why I need to use the sign '=' to implement CommandLineRunner. When I use sign ':'(accord to basic syntax http://kotlinlang.org/docs/reference/interfaces.html) compiler requires a return statement.
#SpringBootApplication
class Application{
#Bean
fun imageProcess(repo: MongoRepository) = CommandLineRunner {
val room2 = Room(id ="1AN1",
primaryUnit = "XYZ")
repo.save(room)}}
#FunctionalInterface
public interface CommandLineRunner {
void run(String... args) throws Exception;}
Well, assuming this compiles (which isn't clear because you are missing the body of the function), then the following is true:
imageProcess returns a CommandLineRunner. You can ommit the braces around the function block and simply use an expression bodied function like you have here.
An expression bodied function is one whose body is an expression (where an expression is a block of code that resolves to a value of a specific type).
https://kotlinlang.org/docs/reference/lambdas.html
Take these as examples:
// 1 + 2 + 3 is an expression that resolves to an Integer value.
// Therefore, the return type is Int
fun intExpression() = 1 + 2 + 3
// false && true is an expression that resolves to a Boolean value.
// Therefore, the return type is Boolean
fun boolExpression() = false && true
// The when here is a fully exhaustive when expression
// It can resolve to an Integer or a String.
// Therefore the return type is the common subtype of both
// Integer and String which happens to be Any (the root of the Kotlin type heirarchy.
fun anyExpression(foo: Boolean) = when(foo) {
true -> 1
else -> "Hello"
}
More formal definition of an expression:
https://blog.kotlin-academy.com/kotlin-programmer-dictionary-statement-vs-expression-e6743ba1aaa0
EDIT 1:
To clarify further, what is actually happening is that you are creating an anonymous implementation of the CommandLineRunner interface. This can only be written in the way you have written it due to the fact the interface defines a single abstract method. This means your CommandLineRunner interface is a SAM type and the compiler is performing SAM type conversion. In other words, you could have written your code like this:
class MyCommandLineRunner(repo: MongoRepository) : CommandLineRunner {
override fun run(args: String) {
// Do stuff...
}
}
fun imageProcess(repo: MongoRepository) = MyCommandLineRunner(repo)
But, you don't need to do that, because the interface has a single abstract method so you can simply define an inline implementation of the interface without having to explicitly override the run function.
Read about SAM types and SAM conversion here:
https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
EDIT 2:
Finally, look here:
https://docs.spring.io/spring-boot/docs/current/api/org/springframework/boot/CommandLineRunner.html
That is the interface you are implementing. As you can see, it does conform to the definition of a SAM type which is why you can create inline implementation of it without explicitly stating the override of the run function. If the interface had an extra method (let's say stop) then you would have to write your anonymous implementation like so:
#Bean
fun imageProcess(repo: MongoRepository) = object : CommandLineRunner {
override fun run(args: String) {
// Do stuff
}
override fun stop() {
// Do stuff
}
}

Creating an enum in Swift, exportable to ObjC, based on another enum: String

I have an enum Foo: String in Swift (therefore not exportable to Objective-C) and I'm trying to create another enum FooObjc in Swift to kinda "wrap" the existent one so that it is 1) available to use in Objective-C and 2) convertable back and forth (Foo <=> FooObjc). The original Foo enum is part of a framework that I don't want to modify. Of course, it's very easy to do what I want if I use a class instead, like this:
#objc public class FooObjc: NSObject {
public private(set) var foo: Foo
#objc public var string: String {
return foo.rawValue
}
#objc public init?(string: NSString) {
guard let foo = Foo(rawValue: string as String) else {
return nil
}
self.foo = foo
}
internal init(foo: Foo) {
self.foo = foo
}
}
(PS: not able to inherit from NSString because the Swift compiler still doesn't accept creating initializers for that class)
Ok, but I definitely don't like this approach because then my Objective-C code will be string-typed. I really want to use an enum instead because after all, that's what it is. This is the least bad working version I could get:
#objc public enum FooObjc: Int, RawRepresentable {
case undefined = -1
case bar
case baz
// omitting many more cases
internal init?(_ foo: Foo?) {
if let foo = foo {
self = fooMapping.filter { $1 == foo }.map { $0.key }.first!
} else {
self = .undefined
}
}
// MARK: - RawRepresentable
public typealias RawValue = String
public init?(rawValue: RawValue) {
let filter = fooMapping.filter { $1?.rawValue == rawValue }
guard filter.count > 0 else {
return nil
}
self = filter.map { $0.key }.first!
}
public var rawValue: RawValue {
switch (self) {
case .undefined: return "undefined"
case .bar: return Foo.bar.rawValue
case .baz: return Foo.baz.rawValue
// omitting many more cases
}
}
}
private let fooMapping: [FooObjc: Foo?] = [
.undefined : nil,
.bar : .bar,
.baz : .baz
// omitting many more cases
]
Notice that:
the fooMapping is useful to avoid one switch-case for each initializer
this undefined case was necessary because in Swift you can have optional enum properties, in Objective-C you can't, so this case will directly map to a Foo? which value is nil.
What worries me here is that I had to write the same cases from the original Foo three times... I'm completely satisfied if I repeat it only twice, but I wasn't able to use the fooMapping in the rawValue property because then I get a cycle between these two.
Note: I'm not sure if this is relevant to the question, but in the original enum, some of the cases have special String attributions, e.g. we have simply case bar but we also have case baz = "something".
So, the question is: does anyone have suggestions to improve this approach or even suggest something completely new that would avoid so much code repetition?
Thank you very much!
What worries me here is that I had to write the same cases from the original Foo three times
Consider an array ["bar", "baz" ...]. By looking at the index of a string in this array and making the necessary adjustments, you can translate from a string to an integer (and thence, via raw value, to a case). By indexing into the array and making the necessary adjustments, you can translate from an integer to a string (and thence, via raw value, to a case). So you will only have to write out the string values once. This eliminates two of your repetitions.
You will still have to write out the case names in the enum declaration, because there's no other way to tell Objective-C the names of the cases. The way to eliminate that repetition, obviously, is to be willing to change the implementation of Foo itself so that it becomes Objective-C-compatible. But you have stated up front that you refuse to do that, so now you must pay the price.

Describing a function parameter that takes a class as an argument in TypeScript

I want to write a function where you parse the class type (the class, not an instance) then the function will instantiate an instance based on that parameter.
This is best explained by example:
//All possible paramter types must inherit from this base class
class Base { public name : string = ''; }
//These are possible classes that could be parsed to the function
class Foo extends Base { constructor() { super(); console.log("Foo instance created"); } }
class Bar extends Base { constructor() { super(); console.log("Bar instance created"); } }
//This function should take a class that inherits from 'Base' as a paramter - then it will create an instance
function Example(param : ?????????) : Base //I don't know what type the 'param' should be
{
return new param(); //Create instance?? How do I do this
}
//This should be the output - if it worked (but it doesn't)
Example(Foo); //Logs "Foo instance created""
Example(Bar); //Logs "Foo instance created""
//So if this worked, it would become possible to do this:
let b : Foo = Example(Foo);
let c : Bar = Example(Bar);
So my questions is: what type would the param for the 'Example' function be? And how would I create an instance of param from within the function.
Note, if this question is a duplicate I apologise - but I don't know the technical name for this process so it is difficult to research.
You want something like this.
function Example<T extends Base>(param: new () => T): T {
return new param();
}
We know that you'll have some type that is a Base. We're going to name it T, and we'll say that T extends Base to enforce that.
We also know that param will construct a T with no parameters. We can write new () => T to describe that.
Basically the way to think about this is that a class has both an instance side and a static side (also called the "constructor" side). In your example, Base, Foo, and Bar on their own have the static side.
The static side for each of them consists of all the static members you specify (and there aren't any in this case), along with the construct signature. In your case, Example takes a constructor expects no arguments, and produces some subtype of Base.

How are overridden properties handled in init blocks?

I'm trying to understand why the following code throws:
open class Base(open val input: String) {
lateinit var derived: String
init {
derived = input.toUpperCase() // throws!
}
}
class Sub(override val input: String) : Base(input)
When invoking this code like this:
println(Sub("test").derived)
it throws an exception, because at the time toUpperCase is called, input resolves to null. I find this counter intuitive: I pass a non-null value to the primary constructor, yet in the init block of the super class it resolves to null?
I think I have a vague idea of what might be going on: since input serves both as a constructor argument as well as a property, the assignment internally calls this.input, but this isn't fully initialized yet. It's really odd: in the IntelliJ debugger, input resolves normally (to the value "test"), but as soon as I invoke the expression evaluation window and inspect input manually, it's suddenly null.
Assuming this is expected behavior, what do you recommend to do instead, i.e. when one needs to initialize fields derived from properties of the same class?
UPDATE:
I've posted two even more concise code snippets that illustrate where the confusion stems from:
https://gist.github.com/mttkay/9fbb0ddf72f471465afc
https://gist.github.com/mttkay/5dc9bde1006b70e1e8ba
The original example is equivalent to the following Java program:
class Base {
private String input;
private String derived;
Base(String input) {
this.input = input;
this.derived = getInput().toUpperCase(); // Initializes derived by calling an overridden method
}
public String getInput() {
return input;
}
}
class Derived extends Base {
private String input;
public Derived(String input) {
super(input); // Calls the superclass constructor, which tries to initialize derived
this.input = input; // Initializes the subclass field
}
#Override
public String getInput() {
return input; // Returns the value of the subclass field
}
}
The getInput() method is overridden in the Sub class, so the code calls Sub.getInput(). At this time, the constructor of the Sub class has not executed, so the backing field holding the value of Sub.input is still null. This is not a bug in Kotlin; you can easily run into the same problem in pure Java code.
The fix is to not override the property. (I've seen your comment, but this doesn't really explain why you think you need to override it.)
The confusion comes from the fact that you created two storages for the input value (fields in JVM). One is in base class, one in derived. When you are reading input value in base class, it calls virtual getInput method under the hood. getInput is overridden in derived class to return its own stored value, which is not initialised before base constructor is called. This is typical "virtual call in constructor" problem.
If you change derived class to actually use property of super type, everything is fine again.
class Sub(input: String) : Base(input) {
override val input : String
get() = super.input
}