Skip to content

Commit

Permalink
GROOVY-4020, GROOVY-5760, GROOVY-7670, GROOVY-9194
Browse files Browse the repository at this point in the history
  • Loading branch information
eric-milles committed May 23, 2022
1 parent 550abd0 commit df01599
Show file tree
Hide file tree
Showing 26 changed files with 644 additions and 112 deletions.
1 change: 1 addition & 0 deletions base/org.codehaus.groovy25/.checkstyle
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
<file-match-pattern match-pattern="groovy/classgen/AsmClassGenerator.java" include-pattern="false" />
<file-match-pattern match-pattern="groovy/classgen/EnumVisitor.java" include-pattern="false" />
<file-match-pattern match-pattern="groovy/classgen/ExtendedVerifier.java" include-pattern="false" />
<file-match-pattern match-pattern="groovy/classgen/GeneratorContext.java" include-pattern="false" />
<file-match-pattern match-pattern="groovy/classgen/Verifier.java" include-pattern="false" />
<file-match-pattern match-pattern="groovy/classgen/asm/CompileStack.java" include-pattern="false" />
<file-match-pattern match-pattern="groovy/classgen/asm/InvocationWriter.java" include-pattern="false" />
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.codehaus.groovy.classgen;

import org.codehaus.groovy.GroovyBugError;
import org.codehaus.groovy.ast.ClassHelper;
import org.codehaus.groovy.ast.ClassNode;
import org.codehaus.groovy.ast.CompileUnit;
import org.codehaus.groovy.ast.MethodNode;


/**
* A context shared across generations of a class and its inner classes
*/
public class GeneratorContext {

private int innerClassIdx = 1;
private int closureClassIdx = 1;
private final CompileUnit compileUnit;

public GeneratorContext(CompileUnit compileUnit) {
this.compileUnit = compileUnit;
}

public GeneratorContext(CompileUnit compileUnit, int innerClassOffset) {
this.compileUnit = compileUnit;
this.innerClassIdx = innerClassOffset;
}

public int getNextInnerClassIdx() {
return innerClassIdx++;
}

public CompileUnit getCompileUnit() {
return compileUnit;
}

public String getNextClosureInnerName(ClassNode owner, ClassNode enclosingClass, MethodNode enclosingMethod) {
String methodName = "";
if (enclosingMethod != null) {
methodName = enclosingMethod.getName();

if (enclosingClass.isDerivedFrom(ClassHelper.CLOSURE_TYPE)) {
methodName = "";
} else {
methodName = "_"+encodeAsValidClassName(methodName);
}
}
return methodName + "_closure" + closureClassIdx++;
}

/* GRECLIPSE edit -- GROOVY-4020, et al.
private static final int MIN_ENCODING = ' ';
private static final int MAX_ENCODING = ']';
private static final boolean[] CHARACTERS_TO_ENCODE = new boolean[MAX_ENCODING-MIN_ENCODING+1];
static {
CHARACTERS_TO_ENCODE[' '-MIN_ENCODING] = true;
CHARACTERS_TO_ENCODE['!'-MIN_ENCODING] = true;
CHARACTERS_TO_ENCODE['/'-MIN_ENCODING] = true;
CHARACTERS_TO_ENCODE['.'-MIN_ENCODING] = true;
CHARACTERS_TO_ENCODE[';'-MIN_ENCODING] = true;
CHARACTERS_TO_ENCODE['$'-MIN_ENCODING] = true;
CHARACTERS_TO_ENCODE['<'-MIN_ENCODING] = true;
CHARACTERS_TO_ENCODE['>'-MIN_ENCODING] = true;
CHARACTERS_TO_ENCODE['['-MIN_ENCODING] = true;
CHARACTERS_TO_ENCODE[']'-MIN_ENCODING] = true;
CHARACTERS_TO_ENCODE[':'-MIN_ENCODING] = true;
CHARACTERS_TO_ENCODE['\\'-MIN_ENCODING] = true;
}
*/
private static final boolean[] CHARACTERS_TO_ENCODE;
private static final int MIN_ENCODING, MAX_ENCODING;
static {
char[] chars = {' ', '!', '"', '#', '$', '&', '\'', '(', ')', '*', '+', ',', '-', '.', '/', ':', ';', '<', '=', '>', '@', '[', '\\', ']', '^', '{', '}', '~'};

MIN_ENCODING = chars[0];
MAX_ENCODING = chars[chars.length - 1];
CHARACTERS_TO_ENCODE = new boolean[MAX_ENCODING - MIN_ENCODING + 1];

for (char c : chars) {
CHARACTERS_TO_ENCODE[c - MIN_ENCODING] = true;
}
}
// GRECLIPSE end

public static String encodeAsValidClassName(String name) {
// GRECLIPSE add -- GROOVY-4020, et al.
if (name.equals("module-info") || name.equals("package-info")) return name;
// GRECLIPSE end
final int l = name.length();
StringBuilder b = null;
int lastEscape = -1;
for(int i = 0; i < l; ++i) {
final int encodeIndex = name.charAt(i) - MIN_ENCODING;
if (encodeIndex >= 0 && encodeIndex < CHARACTERS_TO_ENCODE.length) {
if (CHARACTERS_TO_ENCODE[encodeIndex]) {
if(b == null) {
b = new StringBuilder(name.length() + 3);
b.append(name, 0, i);
} else {
b.append(name, lastEscape + 1, i);
}
b.append('_');
lastEscape = i;
}
}
}
if(b == null) return name;
if (lastEscape == -1) throw new GroovyBugError("unexpected escape char control flow in "+name);
b.append(name, lastEscape + 1, l);
return b.toString();
}
}
1 change: 1 addition & 0 deletions base/org.codehaus.groovy30/.checkstyle
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
<file-match-pattern match-pattern="groovy/classgen/(Annotation|Enum)Visitor.java" include-pattern="false" />
<file-match-pattern match-pattern="groovy/classgen/AsmClassGenerator.java" include-pattern="false" />
<file-match-pattern match-pattern="groovy/classgen/(Extended)?Verifier.java" include-pattern="false" />
<file-match-pattern match-pattern="groovy/classgen/GeneratorContext.java" include-pattern="false" />
<file-match-pattern match-pattern="groovy/classgen/asm/(Invocation|Statement)Writer.java" include-pattern="false" />
<file-match-pattern match-pattern="groovy/classgen/asm/CompileStack.java" include-pattern="false" />
<file-match-pattern match-pattern="groovy/classgen/asm/sc/StaticInvocationWriter.java" include-pattern="false" />
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.codehaus.groovy.classgen;

import org.codehaus.groovy.GroovyBugError;
import org.codehaus.groovy.ast.ClassHelper;
import org.codehaus.groovy.ast.ClassNode;
import org.codehaus.groovy.ast.CompileUnit;
import org.codehaus.groovy.ast.MethodNode;


/**
* A context shared across generations of a class and its inner classes
*/
public class GeneratorContext {

private int innerClassIdx = 1;
private int closureClassIdx = 1;
private int syntheticMethodIdx = 0;
private final CompileUnit compileUnit;

public GeneratorContext(CompileUnit compileUnit) {
this.compileUnit = compileUnit;
}

public GeneratorContext(CompileUnit compileUnit, int innerClassOffset) {
this.compileUnit = compileUnit;
this.innerClassIdx = innerClassOffset;
}

public int getNextInnerClassIdx() {
return innerClassIdx++;
}

public CompileUnit getCompileUnit() {
return compileUnit;
}

public String getNextClosureInnerName(ClassNode owner, ClassNode enclosingClass, MethodNode enclosingMethod) {
return getNextInnerName(owner, enclosingClass, enclosingMethod, "closure");
}

public String getNextLambdaInnerName(ClassNode owner, ClassNode enclosingClass, MethodNode enclosingMethod) {
return getNextInnerName(owner, enclosingClass, enclosingMethod, "lambda");
}

private String getNextInnerName(ClassNode owner, ClassNode enclosingClass, MethodNode enclosingMethod, String classifier) {
String methodName = "";
if (enclosingMethod != null) {
methodName = enclosingMethod.getName();

if (enclosingClass.isDerivedFrom(ClassHelper.CLOSURE_TYPE)) {
methodName = "";
} else {
methodName = "_" + encodeAsValidClassName(methodName);
}
}

return methodName + "_" + classifier + closureClassIdx++;
}

public String getNextConstructorReferenceSyntheticMethodName(MethodNode enclosingMethodNode) {
return "ctorRef$"
+ (null == enclosingMethodNode
? ""
: enclosingMethodNode.getName().replace("<", "").replace(">", "") + "$" )
+ syntheticMethodIdx++;
}

/* GRECLIPSE edit -- GROOVY-4020, et al.
private static final int MIN_ENCODING = ' ';
private static final int MAX_ENCODING = ']';
private static final boolean[] CHARACTERS_TO_ENCODE = new boolean[MAX_ENCODING-MIN_ENCODING+1];
static {
CHARACTERS_TO_ENCODE[' '-MIN_ENCODING] = true;
CHARACTERS_TO_ENCODE['!'-MIN_ENCODING] = true;
CHARACTERS_TO_ENCODE['/'-MIN_ENCODING] = true;
CHARACTERS_TO_ENCODE['.'-MIN_ENCODING] = true;
CHARACTERS_TO_ENCODE[';'-MIN_ENCODING] = true;
CHARACTERS_TO_ENCODE['$'-MIN_ENCODING] = true;
CHARACTERS_TO_ENCODE['<'-MIN_ENCODING] = true;
CHARACTERS_TO_ENCODE['>'-MIN_ENCODING] = true;
CHARACTERS_TO_ENCODE['['-MIN_ENCODING] = true;
CHARACTERS_TO_ENCODE[']'-MIN_ENCODING] = true;
CHARACTERS_TO_ENCODE[':'-MIN_ENCODING] = true;
CHARACTERS_TO_ENCODE['\\'-MIN_ENCODING] = true;
}
*/
private static final boolean[] CHARACTERS_TO_ENCODE;
private static final int MIN_ENCODING, MAX_ENCODING;
static {
char[] chars = {' ', '!', '"', '#', '$', '&', '\'', '(', ')', '*', '+', ',', '-', '.', '/', ':', ';', '<', '=', '>', '@', '[', '\\', ']', '^', '{', '}', '~'};

MIN_ENCODING = chars[0];
MAX_ENCODING = chars[chars.length - 1];
CHARACTERS_TO_ENCODE = new boolean[MAX_ENCODING - MIN_ENCODING + 1];

for (char c : chars) {
CHARACTERS_TO_ENCODE[c - MIN_ENCODING] = true;
}
}
// GRECLIPSE end

public static String encodeAsValidClassName(String name) {
// GRECLIPSE add -- GROOVY-4020, et al.
if (name.equals("module-info") || name.equals("package-info")) return name;
// GRECLIPSE end
final int l = name.length();
StringBuilder b = null;
int lastEscape = -1;
for(int i = 0; i < l; ++i) {
final int encodeIndex = name.charAt(i) - MIN_ENCODING;
if (encodeIndex >= 0 && encodeIndex < CHARACTERS_TO_ENCODE.length) {
if (CHARACTERS_TO_ENCODE[encodeIndex]) {
if(b == null) {
b = new StringBuilder(name.length() + 3);
b.append(name, 0, i);
} else {
b.append(name, lastEscape + 1, i);
}
b.append('_');
lastEscape = i;
}
}
}
if(b == null) return name;
if (lastEscape == -1) throw new GroovyBugError("unexpected escape char control flow in "+name);
b.append(name, lastEscape + 1, l);
return b.toString();
}
}
1 change: 1 addition & 0 deletions base/org.codehaus.groovy40/.checkstyle
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
<file-match-pattern match-pattern="groovy/ast/tools/(Expression|Generics)Utils.java" include-pattern="false" />
<file-match-pattern match-pattern="groovy/classgen/(Annotation|Enum)Visitor.java" include-pattern="false" />
<file-match-pattern match-pattern="groovy/classgen/(Extended)?Verifier.java" include-pattern="false" />
<file-match-pattern match-pattern="groovy/classgen/GeneratorContext.java" include-pattern="false" />
<file-match-pattern match-pattern="groovy/classgen/asm/WriterController.java" include-pattern="false" />
<file-match-pattern match-pattern="groovy/classgen/asm/sc/StaticInvocationWriter.java" include-pattern="false" />
<file-match-pattern match-pattern="groovy/classgen/asm/sc/StaticPropertyAccessHelper.java" include-pattern="false" />
Expand Down
Loading

0 comments on commit df01599

Please sign in to comment.