Getting PSI of C++ class in Android Studio

已回答

Hello, I am developing a plugin for Android Studio that has to match native C++ classes with Java classes. So far, I am using this:

val file = FilenameIndex.getFilesByName(e.project!!, "Calculator.cpp", GlobalSearchScope.everythingScope(e.project!!))[0]
file.accept(object : OCRecursiveVisitor() {
override fun visitMacroCall(macroCall: OCMacroCall?) {
if (!macroCall.resolveToSymbol().name.equals("MyJNIBindingMacro"))
return
val cppClassName = macroCall!!.arguments[0].text
// cppClassName is for example: "MyNamespace::OtherNamespace::Calculator"
val javaClassName = macroCall!!.arguments[1].text
// javaClassName is for example: "com.example.shovel.flower.Calculator"
...
}
}

How can I get a PSI class object for the className I got from the macro? I was able to do it for the java class, but what about the cpp class?

So far I am struggling with usage of CIDR packages, because it lacks documentation/examples. Do you have any hint for me?

I've read on this forum that you intend to rework this system. Can you give me at least a rough estimate of the timeline? So that I know that it makes sense to spend time developing anything for this version.

0

Hi Tom!

Unfortunately, this API is not considered public, so no documentation/examples exist for it. Also, as you mentioned, it's expected to be sunset (we now estimate it late 2022, but that's by no way an official ETA, and can be postponed).

If you want to proceed with it:

The macro expansion is available in the PSI tree as zero-length tokens after the macro call (so you can use `visitStruct` to get the element). If you need to map it back to the macro (i.e. for some highlighting), use `OCElementUtil.getRangeInMacroCall(struct)` (and then possibly `range.getMacroCall()` to get `OCMacroCall`. Most of the useful information about the struct can be accessed via `struct.getSymbol()`. Feel free to ask more specific questions.

0

Hello, thanks for the update. I am going to proceed with the development of the plugin for now.

The hint you gave me is about the macro itself, but my question is more about the class mentioned as an argument for the macro. In the code, it looks like this:

MY_JNI_BINDING_MACRO(MyNamespace::OtherNamespace::Calculator, com.example.shovel.flower.Calculator)

the question is, how can I get to some kind of class representation for the cpp Calculator class (for example to list all public functions in the class).

For example this is how I am getting the equivalent Java class from the fully-qualified name:

val myCls = JavaPsiFacade.getInstance(e.project!!)
.findClass("com.example.shovel.flower.Calculator",
GlobalSearchScope.everythingScope(e.project!!))
// Then I can do this:
val methods = myCls.allMethods

How to do the equivalent of this for the cpp class?

My intent is to create a plugin that would find relationship between c++ MyNamespace::OtherNamespace::Calculator and java com.example.shovel.flower.Calculator. Then I want to implement many things - for example some button to navigate from one to the other, custom inspections, etc.

 

0

I see, sorry for the delay.

 

You need to:

  1. Create an instance of OCQualifiedName:
    val qn = OCQualifiedName.parse(qualifiedNameStr);
  2. use OCGlobalProjectSymbolsCache.processTopLevelSymbols, passing `qn.getName()` as a 3rd parameter
  3. in the processor, use something like
if (symbol !is OCStructSymbol || symbol.isPredeclaration)
return false
val qualifiedSymbolName = symbol.getResolvedQualifiedName(OCResolveContext.forSymbol(symbol, project))
if (qualifiedSymbolName == qn) { // this is your class }

Note that's potentially time-consuming.

0

请先登录再写评论。