Is there a way to create a unique variable name in a given scope?

Given Scope , there is a function that can generate a unique variable name, so that a variable declaration for the unique name can be inserted into scope and the resulting source code / CompilationUnitTree will still be compiled?

+4
source share
1 answer

I ended up writing my own utility function:

 import com.sun.source.tree.Scope; import javax.lang.model.element.Element; import javax.lang.model.element.ElementKind; import static javax.lang.model.element.ElementKind.*; import javax.lang.model.element.Name; import javax.lang.model.util.Elements; import org.apache.commons.lang3.StringUtils; public class ScopeUtils { private Elements elements; public ScopeUtils(Elements elements) { this.elements = elements; } public Name generateUniqueName(Scope scope, CharSequence prefixCs) { String prefix = prefixCs.toString(); // https://issues.apache.org/jira/browse/LANG-786 int i = 0, j = 0; Scope enclosingScope; for (; scope != null && (enclosingScope = scope.getEnclosingScope()) != null; scope = enclosingScope) { for (Element e : scope.getLocalElements()) { ElementKind kind = e.getKind(); String simpleName = e.getSimpleName().toString(); if (kind == LOCAL_VARIABLE || kind == PARAMETER || kind == EXCEPTION_PARAMETER || kind == TYPE_PARAMETER || kind == CLASS || kind == INTERFACE || kind == ENUM || kind == ANNOTATION_TYPE) { if (StringUtils.startsWith(simpleName, prefix)) { if (StringUtils.equals(simpleName, prefix)) { i = Math.max(i, j + 1); } else { try { j = Math.max(j, Integer.parseInt(simpleName.subSequence(prefix.length(), simpleName.length()).toString(), 10)); } catch (NumberFormatException ex) { continue; } if (i > 0) { i = Math.max(i, j + 1); } } } } else { assert kind == FIELD && (StringUtils.equals(simpleName, "super") || StringUtils.equals(simpleName, "this")); } } } return elements.getName(i <= 0 ? prefix : String.format("%s%d", prefix, i)); } } 

This was tested using the following test source file:

 package test.mytest; import org.slf4j.Logger/*INTERFACE*/; import org.slf4j.LoggerFactory/*CLASS*/; import test.mytest.MyEnum/*ENUM*/; import static test.mytest.MyEnum.*; @interface MyAnnotation/*ANNOTATION_TYPE*/ { } interface MyInterface/*INTERFACE*/ { } class MyClass/*CLASS*/ { } public class App/*CLASS*/ { private static final Logger LOGGER = LoggerFactory.getLogger(App.class); private static final String STR1 = "test"; private StringBuilder sb10 = new StringBuilder(); //super/*FIELD*/ //this/*FIELD*/ public <T/*TYPE_PARAMETER*/> void test(T obj/*PARAMETER*/) { MyEnum e/*LOCAL_VARIABLE*/ = TEST1; switch (e) { case TEST1: StringBuilder sb/*LOCAL_VARIABLE*/ = new StringBuilder(); StringBuilder sb1/*LOCAL_VARIABLE*/ = new StringBuilder(); obj = null; if (obj == TEST1) { } try { obj.toString(); } catch (NullPointerException npe/*EXCEPTION_PARAMETER*/) { StringBuilder sb3/*LOCAL_VARIABLE*/ = new StringBuilder(); final String str/*LOCAL_VARIABLE*/ = "hi!"; LOGGER.debug(STR1); } default: break; } } public static void main(String[] args) { new App().<String>test("test"); } } 

where MyEnum declared as:

 package test.mytest; public enum MyEnum { TEST1, TEST2; } 

The scope in LOGGER.debug(STR1); is the scope of the call LOGGER.debug(STR1); in the catch block. Result: "sb4" .

0
source

Source: https://habr.com/ru/post/1391634/


All Articles