forked from JavaTX/JavaCompilerCore
Merge branch 'simplifyRes' of ssh://gohorb.ba-horb.de/bahome/projekt/git/JavaCompilerCore into simplifyRes
This commit is contained in:
commit
eed8f32cb7
@ -3,8 +3,11 @@
|
|||||||
*/
|
*/
|
||||||
package de.dhbwstuttgart.bytecode.simplifyRes;
|
package de.dhbwstuttgart.bytecode.simplifyRes;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import com.google.common.collect.Collections2;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author fayez
|
* @author fayez
|
||||||
*
|
*
|
||||||
@ -12,7 +15,9 @@ import java.util.List;
|
|||||||
public class GenericGeneratorResultsForAllMethods {
|
public class GenericGeneratorResultsForAllMethods {
|
||||||
private final List<MethodAndConstraints> methodsAndConstraints;
|
private final List<MethodAndConstraints> methodsAndConstraints;
|
||||||
|
|
||||||
|
public GenericGeneratorResultsForAllMethods() {
|
||||||
|
this(Collections.emptyList());
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
* @param methodsAndConstraints
|
* @param methodsAndConstraints
|
||||||
*/
|
*/
|
||||||
|
@ -40,9 +40,11 @@ public class GenericGenratorResultForSourceFile {
|
|||||||
public GenericsGeneratorResultForClass getSimplifyResultsByName(String pkgName, String name) {
|
public GenericsGeneratorResultForClass getSimplifyResultsByName(String pkgName, String name) {
|
||||||
|
|
||||||
if (this.pkgName.equals(pkgName)) {
|
if (this.pkgName.equals(pkgName)) {
|
||||||
return genericGeneratorResultForAllClasses.stream().filter(sr -> sr.getClassName().equals(name)).findAny()
|
return genericGeneratorResultForAllClasses
|
||||||
.orElseThrow(() -> new NoSuchElementException(
|
.stream()
|
||||||
"Simplify results for the class " + pkgName + "." + name + " are not found"));
|
.filter(sr -> sr.getClassName().equals(name))
|
||||||
|
.findAny()
|
||||||
|
.orElse(new GenericsGeneratorResultForClass(name));
|
||||||
}
|
}
|
||||||
throw new NoSuchElementException("Simplify results for the class " + pkgName + "." + name + " are not found");
|
throw new NoSuchElementException("Simplify results for the class " + pkgName + "." + name + " are not found");
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
*/
|
*/
|
||||||
package de.dhbwstuttgart.bytecode.simplifyRes;
|
package de.dhbwstuttgart.bytecode.simplifyRes;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -14,6 +15,9 @@ public class GenericsGeneratorResultForClass {
|
|||||||
private final List<GenericsGeneratorResult> classConstraints;
|
private final List<GenericsGeneratorResult> classConstraints;
|
||||||
private final GenericGeneratorResultsForAllMethods methodsAndTheirConstraints;
|
private final GenericGeneratorResultsForAllMethods methodsAndTheirConstraints;
|
||||||
|
|
||||||
|
public GenericsGeneratorResultForClass(String className) {
|
||||||
|
this(className, Collections.emptyList(), new GenericGeneratorResultsForAllMethods());
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
* @param className
|
* @param className
|
||||||
* @param classConstraints
|
* @param classConstraints
|
||||||
@ -52,6 +56,9 @@ public class GenericsGeneratorResultForClass {
|
|||||||
.anyMatch(i -> i.equals(id));
|
.anyMatch(i -> i.equals(id));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public List<GenericsGeneratorResult> getMethodConstraintsByID(String id) {
|
public List<GenericsGeneratorResult> getMethodConstraintsByID(String id) {
|
||||||
return methodsAndTheirConstraints.getMethodsAndConstraints().stream().filter(mc -> mc.getMethodID().equals(id))
|
return methodsAndTheirConstraints.getMethodsAndConstraints().stream().filter(mc -> mc.getMethodID().equals(id))
|
||||||
.findFirst().get().getConstraints();
|
.findFirst().get().getConstraints();
|
||||||
|
@ -59,21 +59,29 @@ import org.apache.commons.io.output.NullOutputStream;
|
|||||||
|
|
||||||
public class JavaTXCompiler {
|
public class JavaTXCompiler {
|
||||||
|
|
||||||
|
public static JavaTXCompiler INSTANCE;
|
||||||
final CompilationEnvironment environment;
|
final CompilationEnvironment environment;
|
||||||
Boolean resultmodel = true;
|
Boolean resultmodel = true;
|
||||||
public final Map<File, SourceFile> sourceFiles = new HashMap<>();
|
public final Map<File, SourceFile> sourceFiles = new HashMap<>();
|
||||||
Boolean log = true; // gibt an ob ein Log-File nach
|
Boolean log = true; //gibt an ob ein Log-File nach System.getProperty("user.dir")+"src/test/java/logFiles" geschrieben werden soll?
|
||||||
// System.getProperty("user.dir")+"src/test/java/logFiles" geschrieben werden
|
|
||||||
// soll?
|
|
||||||
public volatile UnifyTaskModel usedTasks = new UnifyTaskModel();
|
public volatile UnifyTaskModel usedTasks = new UnifyTaskModel();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Äußerste Liste der Source-Files.
|
||||||
|
* Danach Liste der Klassen in Source File.
|
||||||
|
* Danach Map Klassenname
|
||||||
|
*/
|
||||||
|
private List<List<HashMap<String, SimplifyResult>>> simplifyResultsSF = new ArrayList<>();
|
||||||
|
|
||||||
public JavaTXCompiler(File sourceFile) throws IOException, ClassNotFoundException {
|
public JavaTXCompiler(File sourceFile) throws IOException, ClassNotFoundException {
|
||||||
this(Arrays.asList(sourceFile));
|
this(Arrays.asList(sourceFile));
|
||||||
|
INSTANCE = this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public JavaTXCompiler(File sourceFile, Boolean log) throws IOException, ClassNotFoundException {
|
public JavaTXCompiler(File sourceFile, Boolean log) throws IOException, ClassNotFoundException {
|
||||||
this(sourceFile);
|
this(sourceFile);
|
||||||
this.log = log;
|
this.log = log;
|
||||||
|
INSTANCE = this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public JavaTXCompiler(List<File> sources) throws IOException, ClassNotFoundException {
|
public JavaTXCompiler(List<File> sources) throws IOException, ClassNotFoundException {
|
||||||
@ -81,6 +89,7 @@ public class JavaTXCompiler {
|
|||||||
for (File s : sources) {
|
for (File s : sources) {
|
||||||
sourceFiles.put(s, parse(s));
|
sourceFiles.put(s, parse(s));
|
||||||
}
|
}
|
||||||
|
INSTANCE = this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ConstraintSet<Pair> getConstraints() throws ClassNotFoundException {
|
public ConstraintSet<Pair> getConstraints() throws ClassNotFoundException {
|
||||||
@ -93,8 +102,8 @@ public class JavaTXCompiler {
|
|||||||
for (File forSourceFile : sourceFiles.keySet())
|
for (File forSourceFile : sourceFiles.keySet())
|
||||||
for (JavaClassName name : sourceFiles.get(forSourceFile).getImports()) {
|
for (JavaClassName name : sourceFiles.get(forSourceFile).getImports()) {
|
||||||
//TODO: Hier werden imports von eigenen (.jav) Klassen nicht beachtet
|
//TODO: Hier werden imports von eigenen (.jav) Klassen nicht beachtet
|
||||||
ClassOrInterface importedClass = ASTFactory
|
ClassOrInterface importedClass = ASTFactory.createClass(
|
||||||
.createClass(ClassLoader.getSystemClassLoader().loadClass(name.toString()));
|
ClassLoader.getSystemClassLoader().loadClass(name.toString()));
|
||||||
importedClasses.add(importedClass);
|
importedClasses.add(importedClass);
|
||||||
}
|
}
|
||||||
allClasses.addAll(importedClasses);
|
allClasses.addAll(importedClasses);
|
||||||
@ -102,6 +111,18 @@ public class JavaTXCompiler {
|
|||||||
return new TYPE(sourceFiles.values(), allClasses).getConstraints();
|
return new TYPE(sourceFiles.values(), allClasses).getConstraints();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<ClassOrInterface> getAvailableClasses(SourceFile forSourceFile) throws ClassNotFoundException {
|
||||||
|
//PL 2018-09-18: List durch Set ersetzt, damit die Klassen nur einmal hinzugefuegt werden
|
||||||
|
//List<ClassOrInterface> allClasses = new ArrayList<>();//environment.getAllAvailableClasses();
|
||||||
|
Set<ClassOrInterface> allClasses = new HashSet<>();
|
||||||
|
|
||||||
|
/* PL 2018-09-19 geloescht werden bereits in typeInference hinzugefuegt
|
||||||
|
}
|
||||||
|
allClasses.addAll(importedClasses);
|
||||||
|
|
||||||
|
return new TYPE(sourceFiles.values(), allClasses).getConstraints();
|
||||||
|
}
|
||||||
|
|
||||||
public List<ClassOrInterface> getAvailableClasses(SourceFile forSourceFile) throws ClassNotFoundException {
|
public List<ClassOrInterface> getAvailableClasses(SourceFile forSourceFile) throws ClassNotFoundException {
|
||||||
// PL 2018-09-18: List durch Set ersetzt, damit die Klassen nur einmal
|
// PL 2018-09-18: List durch Set ersetzt, damit die Klassen nur einmal
|
||||||
// hinzugefuegt werden
|
// hinzugefuegt werden
|
||||||
@ -711,6 +732,20 @@ public class JavaTXCompiler {
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void generateBytecodForFile(String path, HashMap<String, byte[]> classFiles, SourceFile sf,
|
||||||
|
List<ResultSet> typeinferenceResult) throws IOException {
|
||||||
|
try {
|
||||||
|
List<GenericGenratorResultForSourceFile> genericResults = getGeneratedGenericResultsForAllSourceFiles(typeinferenceResult);
|
||||||
|
BytecodeGen bytecodeGen = new BytecodeGen(classFiles,typeinferenceResult, genericResults, sf,path);
|
||||||
|
bytecodeGen.visit(sf);
|
||||||
|
this.writeClassFile(bytecodeGen.getClassFiles(), path);
|
||||||
|
} catch (ClassNotFoundException e) {
|
||||||
|
// TODO Auto-generated catch block
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public List<GenericGenratorResultForSourceFile> getGeneratedGenericResultsForAllSourceFiles()
|
public List<GenericGenratorResultForSourceFile> getGeneratedGenericResultsForAllSourceFiles()
|
||||||
throws ClassNotFoundException {
|
throws ClassNotFoundException {
|
||||||
List<GenericGenratorResultForSourceFile> result = new ArrayList<>();
|
List<GenericGenratorResultForSourceFile> result = new ArrayList<>();
|
||||||
|
@ -2,6 +2,10 @@ package de.dhbwstuttgart.syntaxtree;
|
|||||||
|
|
||||||
import org.antlr.v4.runtime.Token;
|
import org.antlr.v4.runtime.Token;
|
||||||
|
|
||||||
|
import com.google.common.collect.Lists;
|
||||||
|
|
||||||
|
import de.dhbwstuttgart.parser.NullToken;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
|
|
||||||
@ -16,10 +20,20 @@ public class GenericDeclarationList extends SyntaxTreeNode implements Iterable<G
|
|||||||
private Token offsetOfLastElement;
|
private Token offsetOfLastElement;
|
||||||
private List<GenericTypeVar> gtvs = new ArrayList<>();
|
private List<GenericTypeVar> gtvs = new ArrayList<>();
|
||||||
|
|
||||||
public GenericDeclarationList(List<GenericTypeVar> values, Token endOffset) {
|
@SuppressWarnings("unchecked")
|
||||||
|
public GenericDeclarationList(Iterable<? extends GenericTypeVar> values, Token endOffset) {
|
||||||
|
super(endOffset);
|
||||||
|
gtvs = isListOfGenericTypeVar(values) ? (List<GenericTypeVar>)values : Lists.newArrayList(values);
|
||||||
|
this.offsetOfLastElement = endOffset;
|
||||||
|
}
|
||||||
|
|
||||||
|
public GenericDeclarationList(ArrayList<GenericTypeVar> values, Token endOffset) {
|
||||||
super(endOffset);
|
super(endOffset);
|
||||||
gtvs = values;
|
gtvs = values;
|
||||||
this.offsetOfLastElement = endOffset;
|
this.offsetOfLastElement = endOffset; }
|
||||||
|
|
||||||
|
private boolean isListOfGenericTypeVar(Iterable<? extends GenericTypeVar> values) {
|
||||||
|
return values instanceof List && ((List<?>)values).size() > 0 && ((List<?>)values).get(0) instanceof GenericTypeVar;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -1,11 +1,37 @@
|
|||||||
package de.dhbwstuttgart.typedeployment;
|
package de.dhbwstuttgart.typedeployment;
|
||||||
|
|
||||||
|
import de.dhbwstuttgart.bytecode.Exception.BytecodeGeneratorError;
|
||||||
|
import de.dhbwstuttgart.bytecode.constraint.TPHConstraint;
|
||||||
|
import de.dhbwstuttgart.bytecode.descriptor.TypeToDescriptor;
|
||||||
|
import de.dhbwstuttgart.bytecode.simplifyRes.GenericGenratorResultForSourceFile;
|
||||||
|
import de.dhbwstuttgart.bytecode.simplifyRes.GenericsGeneratorResult;
|
||||||
|
import de.dhbwstuttgart.bytecode.simplifyRes.GenericsGeneratorResultForClass;
|
||||||
|
import de.dhbwstuttgart.bytecode.utilities.MethodUtility;
|
||||||
|
import de.dhbwstuttgart.bytecode.utilities.Resolver;
|
||||||
|
import de.dhbwstuttgart.core.JavaTXCompiler;
|
||||||
|
import de.dhbwstuttgart.parser.NullToken;
|
||||||
import de.dhbwstuttgart.syntaxtree.*;
|
import de.dhbwstuttgart.syntaxtree.*;
|
||||||
|
import de.dhbwstuttgart.syntaxtree.statement.NewArray;
|
||||||
import de.dhbwstuttgart.syntaxtree.type.*;
|
import de.dhbwstuttgart.syntaxtree.type.*;
|
||||||
import de.dhbwstuttgart.typeinference.result.*;
|
import de.dhbwstuttgart.typeinference.result.*;
|
||||||
import org.antlr.v4.runtime.Token;
|
|
||||||
|
|
||||||
|
import org.antlr.v4.parse.ANTLRParser.action_return;
|
||||||
|
import org.antlr.v4.parse.ANTLRParser.block_return;
|
||||||
|
import org.antlr.v4.parse.ANTLRParser.labeledAlt_return;
|
||||||
|
import org.antlr.v4.parse.ANTLRParser.parserRule_return;
|
||||||
|
import org.antlr.v4.runtime.Token;
|
||||||
|
import org.objectweb.asm.Type;
|
||||||
|
import org.stringtemplate.v4.compiler.STParser.ifstat_return;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.Serializable;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
import java.util.Map.Entry;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import javax.print.DocFlavor.STRING;
|
||||||
|
import javax.security.auth.kerberos.KerberosKey;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TODO:
|
* TODO:
|
||||||
@ -29,61 +55,89 @@ public class TypeInsertFactory {
|
|||||||
|
|
||||||
public static TypeInsert createInsertPoints(RefTypeOrTPHOrWildcardOrGeneric type, Token offset, ClassOrInterface cl, Method m,
|
public static TypeInsert createInsertPoints(RefTypeOrTPHOrWildcardOrGeneric type, Token offset, ClassOrInterface cl, Method m,
|
||||||
ResultSet resultSet) {
|
ResultSet resultSet) {
|
||||||
|
|
||||||
|
try {
|
||||||
ResolvedType resolvedType = resultSet.resolveType(type);
|
ResolvedType resolvedType = resultSet.resolveType(type);
|
||||||
TypeInsertPoint insertPoint = new TypeInsertPoint(offset,
|
TypeInsertPoint insertPoint = new TypeInsertPoint(offset,
|
||||||
new TypeToInsertString(resolvedType.resolvedType).insert);
|
new TypeToInsertString(resolvedType.resolvedType).insert);
|
||||||
|
List<GenericGenratorResultForSourceFile> simplifyResults = JavaTXCompiler.INSTANCE.getGeneratedGenericResultsForAllSourceFiles();
|
||||||
|
for (GenericGenratorResultForSourceFile simplifyResultsEntries : simplifyResults) {
|
||||||
|
GenericsGeneratorResultForClass genericResultsForClass = simplifyResultsEntries.getSimplifyResultsByName("", cl.getClassName().toString());
|
||||||
|
return new TypeInsert(insertPoint, createGenericInsert(genericResultsForClass, cl, m, resultSet), resolvedType.getResultPair());
|
||||||
|
}
|
||||||
|
|
||||||
return new TypeInsert(insertPoint, new HashSet<>(), resolvedType.getResultPair());
|
return new TypeInsert(insertPoint, new HashSet<>(), resolvedType.getResultPair());
|
||||||
|
} catch (ClassNotFoundException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static TypeInsertPoint createGenericInsert(Set<GenericInsertPair> toInsert, ClassOrInterface cl, Method m){
|
private static synchronized Set<TypeInsertPoint> createGenericInsert(GenericsGeneratorResultForClass genericResult, ClassOrInterface cl, Method m, ResultSet resultSet){
|
||||||
//Momentan wird Methode ignoriert. Parameter werden immer als Klassenparameter angefügt:
|
Set<TypeInsertPoint> result = createGenericClassInserts(genericResult, cl);
|
||||||
//Offset zum Einstzen bestimmen:
|
|
||||||
Token offset;
|
for (Method method : cl.getMethods()) {
|
||||||
String insert = "";
|
Resolver resolver = new Resolver(resultSet);
|
||||||
String end;
|
List<GenericsGeneratorResult> methodConstraints = genericResult.getMethodConstraintsByID(MethodUtility.createID(resolver, method));
|
||||||
if(cl.getGenerics().iterator().hasNext()){
|
createMethodConstraints(method, methodConstraints);
|
||||||
//offset = cl.getGenerics().iterator().next().getOffset();
|
}
|
||||||
offset = cl.getGenerics().getOffset();
|
|
||||||
end=",";
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Set<TypeInsertPoint> createMethodConstraints(Method method, List<GenericsGeneratorResult> constraints) {
|
||||||
|
Set<TypeInsertPoint> result = new HashSet<>();
|
||||||
|
Token offset = new GenericDeclarationList(method.getGenerics(), new NullToken()).getOffset();
|
||||||
|
|
||||||
|
if (constraints.size() == 0) {
|
||||||
|
result.add(new TypeInsertPoint(offset, ""));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
String insert = " <";
|
||||||
|
|
||||||
|
for (GenericsGeneratorResult genericInsertConstraint : constraints) {
|
||||||
|
if (genericInsertConstraint.getConstraint().getRight().equals(Type.getInternalName(Object.class))) {
|
||||||
|
insert += genericInsertConstraint.getConstraint().getLeft();
|
||||||
} else {
|
} else {
|
||||||
offset = cl.getGenerics().getOffset();
|
insert += genericInsertConstraint.getConstraint().getLeft() + " extends " + genericInsertConstraint.getConstraint().getRight() + ", ";
|
||||||
insert += "<";
|
|
||||||
end = ">";
|
|
||||||
}
|
|
||||||
|
|
||||||
//Alle einzusetzenden Generics und deren Bounds bestimmen:
|
|
||||||
HashMap<TypePlaceholder, HashSet<TypePlaceholder>> genericsAndBounds = new HashMap<>();
|
|
||||||
for(GenericInsertPair p : toInsert){
|
|
||||||
if(!genericsAndBounds.containsKey(p.TA1)){
|
|
||||||
genericsAndBounds.put((TypePlaceholder) p.TA1, new HashSet<>());
|
|
||||||
}
|
|
||||||
if(p.TA2 != null){
|
|
||||||
genericsAndBounds.get(p.TA1).add((TypePlaceholder) p.TA2);
|
|
||||||
if(!genericsAndBounds.containsKey(p.TA2)){
|
|
||||||
genericsAndBounds.put((TypePlaceholder) p.TA2, new HashSet<>());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//String zum Einsetzen (Generics mit bounds) generieren:
|
insert = insert.substring(0, insert.length() -2);
|
||||||
Iterator<TypePlaceholder> it = genericsAndBounds.keySet().iterator();
|
insert += ">";
|
||||||
if(! it.hasNext())return new TypeInsertPoint(offset, "");
|
|
||||||
while(it.hasNext()){
|
result.add(new TypeInsertPoint(offset, insert));
|
||||||
TypePlaceholder tph = it.next();
|
return result;
|
||||||
insert += tph.getName();
|
}
|
||||||
Set<TypePlaceholder> bounds = genericsAndBounds.get(tph);
|
|
||||||
if(bounds.size() > 0){
|
private static Set<TypeInsertPoint> createGenericClassInserts(GenericsGeneratorResultForClass genericResult, ClassOrInterface cl) {
|
||||||
insert += " extends ";
|
Set<TypeInsertPoint> result = new HashSet<>();
|
||||||
Iterator<TypePlaceholder> boundIt = bounds.iterator();
|
Token offset = cl.getGenerics().getOffset();
|
||||||
while(boundIt.hasNext()){
|
|
||||||
TypePlaceholder bound = boundIt.next();
|
List<GenericsGeneratorResult> classConstraints = genericResult.getClassConstraints();
|
||||||
insert += bound.getName();
|
|
||||||
if(boundIt.hasNext())insert += " & ";
|
if (classConstraints.size() == 0) {
|
||||||
|
result.add(new TypeInsertPoint(offset, ""));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
String insert = " <";
|
||||||
|
|
||||||
|
for (GenericsGeneratorResult genericInsertConstraint : classConstraints) {
|
||||||
|
if (genericInsertConstraint.getConstraint().getRight().equals(Type.getInternalName(Object.class))) {
|
||||||
|
insert += genericInsertConstraint.getConstraint().getLeft();
|
||||||
|
} else {
|
||||||
|
insert += genericInsertConstraint.getConstraint().getLeft() + " extends " + genericInsertConstraint.getConstraint().getRight() + ", ";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(it.hasNext())insert+=",";
|
|
||||||
}
|
insert = insert.substring(0, insert.length() -2);
|
||||||
return new TypeInsertPoint(offset, insert + end);
|
insert += ">";
|
||||||
|
|
||||||
|
result.add(new TypeInsertPoint(offset, insert));
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user