Skip to content

Commit 5e842e8

Browse files
Merge branch 'main' into greg-antlr-trim-whitespace
2 parents 031c145 + bbede7e commit 5e842e8

24 files changed

Lines changed: 101 additions & 55 deletions

rewrite-kotlin/src/main/java/org/openrewrite/kotlin/internal/KotlinPrinter.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -728,7 +728,7 @@ private J.ClassDeclaration visitClassDeclaration0(J.ClassDeclaration classDecl,
728728
visitContainer("where", typeConstraints.getPadding().getConstraints(), JContainer.Location.TYPE_PARAMETERS, ",", "", p);
729729
}
730730

731-
if (!classDecl.getBody().getMarkers().findFirst(OmitBraces.class).isPresent()) {
731+
if (classDecl.getBody() != null && !classDecl.getBody().getMarkers().findFirst(OmitBraces.class).isPresent()) {
732732
visit(classDecl.getBody(), p);
733733
}
734734
afterSyntax(classDecl, p);

rewrite-kotlin/src/test/java/org/openrewrite/kotlin/KotlinTemplateTest.java

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,10 @@
2222
import org.openrewrite.java.tree.J;
2323
import org.openrewrite.test.RewriteTest;
2424

25+
import org.openrewrite.java.JavaTemplate;
26+
import org.openrewrite.java.tree.Statement;
27+
import org.openrewrite.test.TypeValidation;
28+
2529
import java.net.URISyntaxException;
2630
import java.nio.file.Path;
2731
import java.util.List;
@@ -61,6 +65,45 @@ fun foo() {
6165
));
6266
}
6367

68+
@Test
69+
void addStatementToMethodInClass() {
70+
rewriteRun(
71+
spec -> spec.typeValidationOptions(TypeValidation.none())
72+
.recipe(toRecipe(() -> new KotlinVisitor<>() {
73+
@Override
74+
public J visitMethodDeclaration(J.MethodDeclaration method, ExecutionContext ctx) {
75+
J.MethodDeclaration m = (J.MethodDeclaration) super.visitMethodDeclaration(method, ctx);
76+
if (m.getSimpleName().equals("configure")) {
77+
List<Statement> statements = m.getBody().getStatements();
78+
if (statements.stream().noneMatch(s -> s.toString().contains("println"))) {
79+
return JavaTemplate.builder("println(\"added\")")
80+
.contextSensitive()
81+
.build()
82+
.apply(getCursor(), statements.get(statements.size() - 1).getCoordinates().after());
83+
}
84+
}
85+
return m;
86+
}
87+
})),
88+
kotlin(
89+
"""
90+
class MyConfig {
91+
fun configure(value: Int) {
92+
val x = value + 1
93+
}
94+
}
95+
""",
96+
"""
97+
class MyConfig {
98+
fun configure(value: Int) {
99+
val x = value + 1
100+
println("added")
101+
}
102+
}
103+
"""
104+
));
105+
}
106+
64107
@Test
65108
void parserClasspath() {
66109
rewriteRun(

rewrite-python/rewrite/src/rewrite/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
# helps pytest to rewrite the assert statements in test.py
44
try:
5-
import pytest # ty: ignore[unresolved-import]
5+
import pytest
66
pytest.register_assert_rewrite("rewrite.test")
77
except ImportError:
88
pass # pytest not available, skip assert rewriting

rewrite-python/rewrite/src/rewrite/java/extensions.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ def visit_container(v: 'JavaVisitor', container: Optional[JContainer[J2]], p: P)
1717
v.cursor = Cursor(v.cursor, container)
1818
before = v.visit_space(container.before, p)
1919
js = list_map(lambda el: v.visit_right_padded(el, p), container.padding.elements)
20-
v.cursor = v.cursor.parent # ty: ignore[invalid-assignment] # cursor.parent is Optional[Cursor]; ty#1379
20+
v.cursor = v.cursor.parent # ty: ignore[invalid-assignment] # cursor.parent is Optional[Cursor] (ty#628)
2121

2222
return container if js is container.padding.elements and before is container.before else JContainer(before, js, container.markers)
2323

@@ -30,7 +30,7 @@ def visit_right_padded(v: 'JavaVisitor', right: Optional[JRightPadded[T]], p: P)
3030
v.cursor = Cursor(v.cursor, right)
3131
if isinstance(t, Tree):
3232
t = v.visit_and_cast(t, T, p)
33-
v.cursor = v.cursor.parent # ty: ignore[invalid-assignment] # cursor.parent is Optional[Cursor]; ty#1379
33+
v.cursor = v.cursor.parent # ty: ignore[invalid-assignment] # cursor.parent is Optional[Cursor] (ty#628)
3434

3535
if t is None:
3636
return None
@@ -50,7 +50,7 @@ def visit_left_padded(v: 'JavaVisitor', left: Optional[JLeftPadded[T]], p: P) ->
5050
t = left.element
5151
if isinstance(t, Tree):
5252
t = v.visit_and_cast(t, T, p)
53-
v.cursor = v.cursor.parent # ty: ignore[invalid-assignment] # cursor.parent is Optional[Cursor]; ty#1379
53+
v.cursor = v.cursor.parent # ty: ignore[invalid-assignment] # cursor.parent is Optional[Cursor] (ty#628)
5454

5555
if left.element is t and before is left.before:
5656
return left

rewrite-python/rewrite/src/rewrite/java/support_types.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -589,5 +589,5 @@ def build_nullable(cls, before: Optional[JContainer[J2]], elements: Optional[Lis
589589
def empty(cls) -> JContainer[J2]:
590590
if cls._EMPTY is None:
591591
cls._EMPTY = JContainer(Space.EMPTY, [], Markers.EMPTY)
592-
return cls._EMPTY # type: ignore[return-value] # _EMPTY is JContainer[J] but J2 is bound to J
592+
return cls._EMPTY # ty: ignore[invalid-return-type] # _EMPTY is JContainer[J] but J2 is bound to J
593593

rewrite-python/rewrite/src/rewrite/java/support_types.pyi

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ from rewrite.utils import replace_if_changed
2121
class J(Tree):
2222
@property
2323
def prefix(self) -> Space: ...
24+
def replace(self, **kwargs: Any) -> Self: ...
2425
def is_acceptable(self, v: TreeVisitor[Any, P], p: P) -> bool: ...
2526
def accept(self, v: TreeVisitor[Any, P], p: P) -> Optional[Any]: ...
2627
def accept_java(self, v: 'JavaVisitor[P]', p: P) -> Optional['J']: ...
@@ -116,12 +117,14 @@ class JavaType(ABC):
116117
@property
117118
def bounds(self) -> List[JavaType]: ...
118119

120+
@dataclass
119121
class Union:
120122
_bounds: Optional[List[JavaType]]
121123

122124
@property
123125
def bounds(self) -> List[JavaType]: ...
124126

127+
@dataclass
125128
class Intersection:
126129
_bounds: Optional[List[JavaType]]
127130

rewrite-python/rewrite/src/rewrite/parser.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,7 @@ def with_erroneous(self, erroneous: Optional[SourceFile]) -> 'ParseError':
141141
return self if erroneous is self._erroneous else replace(self, _erroneous=erroneous)
142142

143143
def printer(self, cursor: Cursor) -> TreeVisitor[Tree, PrintOutputCapture[P]]:
144-
return PrinterFactory.current().create_printer(cursor) # ty: ignore[unresolved-attribute] # PrinterFactory.current() is always set
144+
return PrinterFactory.current().create_printer(cursor) # ty: ignore[unresolved-attribute] # guarded: PrinterFactory.current() always set here
145145

146146
def is_acceptable(self, v: TreeVisitor[Any, P], p: P) -> bool:
147147
return v.is_adaptable_to(ParseErrorVisitor)

rewrite-python/rewrite/src/rewrite/python/_parser_visitor.py

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -774,7 +774,7 @@ def visit_Import(self, node):
774774
prefix = self.__source_before('import')
775775
imp = self.__convert(node.names[0])
776776
assert imp is not None
777-
return imp.replace(prefix=prefix, qualid=imp.qualid.replace(prefix=imp.prefix))
777+
return imp.replace(prefix=prefix, qualid=imp.qualid.replace(prefix=imp.prefix)) # ty: ignore[unresolved-attribute] # imp is Import at runtime
778778

779779
prefix = self.__source_before('import')
780780
names_prefix = self.__whitespace()
@@ -1197,7 +1197,7 @@ def __convert_match_pattern(self, node):
11971197
py.MatchCase.Pattern.Kind.GROUP,
11981198
JContainer(
11991199
prefix,
1200-
[JRightPadded(inner.replace(prefix=inner_prefix) if hasattr(inner, 'replace') else inner, Space.EMPTY, Markers.EMPTY)], # ty: ignore[call-non-callable]
1200+
[JRightPadded(inner.replace(prefix=inner_prefix) if hasattr(inner, 'replace') else inner, Space.EMPTY, Markers.EMPTY)],
12011201
Markers.EMPTY
12021202
),
12031203
None
@@ -2243,7 +2243,7 @@ def __map_decorator(self, decorator) -> j.Annotation:
22432243
name = name.replace(prefix=extra_parens[-1][1]) # ty: ignore[unresolved-attribute] # recursive call returns unknown
22442244

22452245
# Wrap in extra parentheses (innermost to outermost)
2246-
wrapped: Expression = name
2246+
wrapped: Expression = name # ty: ignore[invalid-assignment]
22472247
for i in range(len(extra_parens) - 1, -1, -1):
22482248
paren_prefix, _ = extra_parens[i]
22492249
suffix = self.__whitespace()
@@ -2769,7 +2769,7 @@ def __convert_type(self, node) -> Optional[TypeTree]:
27692769
prefix = self.__whitespace()
27702770
converted_type = self.__convert_internal(node, self.__convert_type, self.__convert_type_mapper)
27712771
if isinstance(converted_type, TypeTree):
2772-
return converted_type.replace(prefix=prefix) # ty: ignore[unresolved-attribute] # TypeTree base class doesn't have replace
2772+
return converted_type.replace(prefix=prefix) # TypeTree base class doesn't have replace
27732773
else:
27742774
return py.ExpressionTypeTree(
27752775
random_id(),
@@ -3065,14 +3065,14 @@ def ident_or_field(parts: List[str]) -> NameTree:
30653065
return ident_or_field(name.split('.'))
30663066

30673067
def __convert_all(self, trees: Sequence) -> List[J2]:
3068-
return [c for tree in trees if (c := self.__convert(tree)) is not None] # ty: ignore[invalid-return-type]
3068+
return [c for tree in trees if (c := self.__convert(tree)) is not None] # ty: ignore[invalid-return-type] # J list, J2 is bound to J
30693069

30703070
def __convert_block(self, statements: Sequence[Statement], delim: str = ':') -> j.Block:
30713071
prefix = self.__source_before(delim)
30723072
if statements:
3073-
statements = [self.__pad_statement(cast(ast.stmt, s)) for s in statements] # ty: ignore[invalid-assignment]
3073+
statements = [self.__pad_statement(cast(ast.stmt, s)) for s in statements] # ty: ignore[invalid-assignment] # padded statement list type
30743074
else:
3075-
statements = [self.__pad_right(j.Empty(random_id(), Space.EMPTY, Markers.EMPTY), Space.EMPTY)] # ty: ignore[invalid-assignment]
3075+
statements = [self.__pad_right(j.Empty(random_id(), Space.EMPTY, Markers.EMPTY), Space.EMPTY)] # ty: ignore[invalid-assignment] # padded statement list type
30763076
return j.Block(
30773077
random_id(),
30783078
prefix,
@@ -3095,7 +3095,7 @@ def __pad_statement(self, stmt: ast.stmt) -> JRightPadded[Statement]:
30953095
self._token_idx = save_idx
30963096
padding = Space.EMPTY
30973097
markers = Markers.EMPTY
3098-
return JRightPadded(statement, padding, markers) # ty: ignore[invalid-return-type] # statement is J|None from __convert_statement
3098+
return JRightPadded(statement, padding, markers) # ty: ignore[invalid-return-type] # statement is J from __convert_statement
30993099

31003100
def __pad_list_element(self, element: J2, last: bool = False, pad_last: bool = True, delim: str = ',',
31013101
end_delim: Optional[str] = None) -> JRightPadded[J2]:

rewrite-python/rewrite/src/rewrite/python/_py2_parser_visitor.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,7 @@ def _convert_leaf(self, leaf: parso_tree.PythonLeaf) -> Optional[j.J]:
172172
prefix = self._parse_space(leaf.prefix)
173173

174174
# parso 0.7.x uses lowercase type names (e.g. 'name', 'number')
175-
leaf_type = leaf.type.upper()
175+
leaf_type = leaf.type.upper() # ty: ignore[unresolved-attribute] # parso leaf.type is always str
176176

177177
if leaf_type == 'NAME' or leaf_type == 'KEYWORD':
178178
return j.Identifier(

rewrite-python/rewrite/src/rewrite/python/format/blank_lines.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ def visit_compilation_unit(self, cu: CompilationUnit, p: P) -> J:
2222
return super().visit_compilation_unit(cu, p)
2323

2424
def visit_statement(self, stmt: Statement, p: P) -> J:
25-
stmt = super().visit_statement(stmt, p)
25+
stmt = super().visit_statement(stmt, p) # ty: ignore[invalid-assignment] # visitor covariance
2626

2727
parent_cursor = self.cursor.parent_tree_cursor()
2828
top_level = isinstance(parent_cursor.value, CompilationUnit)
@@ -41,7 +41,7 @@ def visit_statement(self, stmt: Statement, p: P) -> J:
4141
else:
4242
min_lines = max(self._style.minimum.around_top_level_classes_functions if isinstance(stmt, (ClassDeclaration, MethodDeclaration)) else 0,
4343
self._style.minimum.after_top_level_imports if prev_import else 0)
44-
stmt = _adjusted_lines_for_tree(stmt, min_lines, self._style.keep_maximum.in_declarations)
44+
stmt = _adjusted_lines_for_tree(stmt, min_lines, self._style.keep_maximum.in_declarations) # ty: ignore[invalid-assignment] # visitor covariance
4545
else:
4646
in_block = isinstance(parent_cursor.value, Block)
4747
in_class = in_block and isinstance(parent_cursor.parent_tree_cursor().value, ClassDeclaration)
@@ -63,7 +63,7 @@ def visit_statement(self, stmt: Statement, p: P) -> J:
6363
if prev_import:
6464
min_lines = max(min_lines, self._style.minimum.after_local_imports)
6565

66-
stmt = _adjusted_lines_for_tree(stmt, min_lines, max_lines)
66+
stmt = _adjusted_lines_for_tree(stmt, min_lines, max_lines) # ty: ignore[invalid-assignment] # visitor covariance
6767
return stmt
6868

6969
def post_visit(self, tree: T, p: P) -> Optional[T]:

0 commit comments

Comments
 (0)