#1056 Making sure indentation level in formatting writer never goes below 0

This commit is contained in:
Gunnar Morling 2017-02-04 21:39:36 +01:00 committed by Andreas Gudian
parent 40fc5612cb
commit 5564c53f41
7 changed files with 200 additions and 10 deletions

View File

@ -117,11 +117,11 @@ class IndentationCorrectingWriter extends Writer {
switch ( c ) { switch ( c ) {
case '{': case '{':
case '(': case '(':
context.indentationLevel++; context.incrementIndentationLevel();
return IN_TEXT; return IN_TEXT;
case '}': case '}':
case ')': case ')':
context.indentationLevel--; context.decrementIndentationLevel();
return IN_TEXT; return IN_TEXT;
case '\"': case '\"':
return IN_STRING; return IN_STRING;
@ -139,10 +139,11 @@ class IndentationCorrectingWriter extends Writer {
*/ */
@Override @Override
void doOnEntry(StateContext context) throws IOException { void doOnEntry(StateContext context) throws IOException {
context.writer.write( getIndentation( context.indentationLevel ) ); context.writer.write( getIndentation( context.getIndentationLevel() ) );
if ( DEBUG ) { if ( DEBUG ) {
System.out.print( new String( getIndentation( context.indentationLevel ) ).replace( " ", "_" ) ); System.out.print( new String( getIndentation( context.getIndentationLevel() ) )
.replace( " ", "_" ) );
} }
} }
@ -173,11 +174,11 @@ class IndentationCorrectingWriter extends Writer {
switch ( c ) { switch ( c ) {
case '{': case '{':
case '(': case '(':
context.indentationLevel++; context.incrementIndentationLevel();
return IN_TEXT; return IN_TEXT;
case '}': case '}':
case ')': case ')':
context.indentationLevel--; context.decrementIndentationLevel();
return IN_TEXT; return IN_TEXT;
case '\"': case '\"':
return IN_STRING; return IN_STRING;
@ -298,14 +299,14 @@ class IndentationCorrectingWriter extends Writer {
switch ( c ) { switch ( c ) {
case '{': case '{':
case '(': case '(':
context.indentationLevel++; context.incrementIndentationLevel();
return START_OF_LINE; return START_OF_LINE;
case '}': case '}':
if ( context.consecutiveLineBreaks > 0 ) { if ( context.consecutiveLineBreaks > 0 ) {
context.consecutiveLineBreaks = 0; // remove previous blank lines context.consecutiveLineBreaks = 0; // remove previous blank lines
} }
case ')': case ')':
context.indentationLevel--; context.decrementIndentationLevel();
return START_OF_LINE; return START_OF_LINE;
case '\r': case '\r':
return isWindows() ? IN_LINE_BREAK : AFTER_LINE_BREAK; return isWindows() ? IN_LINE_BREAK : AFTER_LINE_BREAK;
@ -407,7 +408,7 @@ class IndentationCorrectingWriter extends Writer {
/** /**
* Keeps track of the current indentation level, as implied by brace characters. * Keeps track of the current indentation level, as implied by brace characters.
*/ */
int indentationLevel; private int indentationLevel;
/** /**
* The number of consecutive line-breaks when within {@link State#AFTER_LINE_BREAK}. * The number of consecutive line-breaks when within {@link State#AFTER_LINE_BREAK}.
@ -423,5 +424,22 @@ class IndentationCorrectingWriter extends Writer {
this.lastStateChange = off; this.lastStateChange = off;
this.currentIndex = 0; this.currentIndex = 0;
} }
void incrementIndentationLevel() {
indentationLevel++;
}
void decrementIndentationLevel() {
// decrementing below 0 indicates misbalanced braces in the code, typically because too many closing braces
// are given in an expression; we let that code pass through, the compiler will complain eventually about
// the malformed source file
if ( indentationLevel > 0 ) {
indentationLevel--;
}
}
int getIndentationLevel() {
return indentationLevel;
}
} }
} }

View File

@ -0,0 +1,29 @@
/**
* Copyright 2012-2017 Gunnar Morling (http://www.gunnarmorling.de/)
* and/or other contributors as indicated by the @authors tag. See the
* copyright.txt file in the distribution for a full listing of all
* contributors.
*
* Licensed 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.mapstruct.ap.test.erroneous.misbalancedbraces;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
@Mapper
public interface MapperWithMalformedExpression {
@Mapping(target = "foo", expression = "java( Boolean.valueOf( source.foo > 0 ) ) )")
Target sourceToTarget(Source source);
}

View File

@ -0,0 +1,54 @@
/**
* Copyright 2012-2017 Gunnar Morling (http://www.gunnarmorling.de/)
* and/or other contributors as indicated by the @authors tag. See the
* copyright.txt file in the distribution for a full listing of all
* contributors.
*
* Licensed 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.mapstruct.ap.test.erroneous.misbalancedbraces;
import javax.tools.Diagnostic.Kind;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mapstruct.ap.testutil.IssueKey;
import org.mapstruct.ap.testutil.WithClasses;
import org.mapstruct.ap.testutil.compilation.annotation.CompilationResult;
import org.mapstruct.ap.testutil.compilation.annotation.Diagnostic;
import org.mapstruct.ap.testutil.compilation.annotation.DisableCheckstyle;
import org.mapstruct.ap.testutil.compilation.annotation.ExpectedCompilationOutcome;
import org.mapstruct.ap.testutil.runner.AnnotationProcessorTestRunner;
/**
* Test for making sure that expressions with too many closing braces are passed through, letting the compiler raise an
* error.
*
* @author Gunnar Morling
*/
@WithClasses({ MapperWithMalformedExpression.class, Source.class, Target.class })
@DisableCheckstyle
@RunWith(AnnotationProcessorTestRunner.class)
public class MisbalancedBracesTest {
// the compiler messages due to the additional closing brace differ between JDK and Eclipse, hence we can only
// assert on the line number but not the message
@Test
@IssueKey("1056")
@ExpectedCompilationOutcome(
value = CompilationResult.FAILED,
diagnostics = { @Diagnostic(kind = Kind.ERROR, line = 20) }
)
public void expressionWithMisbalancedBracesIsPassedThrough() {
}
}

View File

@ -0,0 +1,25 @@
/**
* Copyright 2012-2017 Gunnar Morling (http://www.gunnarmorling.de/)
* and/or other contributors as indicated by the @authors tag. See the
* copyright.txt file in the distribution for a full listing of all
* contributors.
*
* Licensed 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.mapstruct.ap.test.erroneous.misbalancedbraces;
public class Source {
//CHECKSTYLE:OFF
public int foo;
}

View File

@ -0,0 +1,25 @@
/**
* Copyright 2012-2017 Gunnar Morling (http://www.gunnarmorling.de/)
* and/or other contributors as indicated by the @authors tag. See the
* copyright.txt file in the distribution for a full listing of all
* contributors.
*
* Licensed 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.mapstruct.ap.test.erroneous.misbalancedbraces;
public class Target {
//CHECKSTYLE:OFF
public boolean foo;
}

View File

@ -0,0 +1,34 @@
/**
* Copyright 2012-2017 Gunnar Morling (http://www.gunnarmorling.de/)
* and/or other contributors as indicated by the @authors tag. See the
* copyright.txt file in the distribution for a full listing of all
* contributors.
*
* Licensed 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.mapstruct.ap.testutil.compilation.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Disables CheckStyle for the sources generated by this test.
*
* @author Gunnar Morling
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface DisableCheckstyle {
}

View File

@ -43,6 +43,7 @@ import org.mapstruct.ap.testutil.WithClasses;
import org.mapstruct.ap.testutil.WithServiceImplementation; import org.mapstruct.ap.testutil.WithServiceImplementation;
import org.mapstruct.ap.testutil.WithServiceImplementations; import org.mapstruct.ap.testutil.WithServiceImplementations;
import org.mapstruct.ap.testutil.compilation.annotation.CompilationResult; import org.mapstruct.ap.testutil.compilation.annotation.CompilationResult;
import org.mapstruct.ap.testutil.compilation.annotation.DisableCheckstyle;
import org.mapstruct.ap.testutil.compilation.annotation.ExpectedCompilationOutcome; import org.mapstruct.ap.testutil.compilation.annotation.ExpectedCompilationOutcome;
import org.mapstruct.ap.testutil.compilation.annotation.ProcessorOption; import org.mapstruct.ap.testutil.compilation.annotation.ProcessorOption;
import org.mapstruct.ap.testutil.compilation.annotation.ProcessorOptions; import org.mapstruct.ap.testutil.compilation.annotation.ProcessorOptions;
@ -78,6 +79,7 @@ abstract class CompilingStatement extends Statement {
private final FrameworkMethod method; private final FrameworkMethod method;
private final CompilationCache compilationCache; private final CompilationCache compilationCache;
private final boolean runCheckstyle;
private Statement next; private Statement next;
private String classOutputDir; private String classOutputDir;
@ -88,6 +90,7 @@ abstract class CompilingStatement extends Statement {
CompilingStatement(FrameworkMethod method, CompilationCache compilationCache) { CompilingStatement(FrameworkMethod method, CompilationCache compilationCache) {
this.method = method; this.method = method;
this.compilationCache = compilationCache; this.compilationCache = compilationCache;
this.runCheckstyle = !method.getMethod().getDeclaringClass().isAnnotationPresent( DisableCheckstyle.class );
this.compilationRequest = new CompilationRequest( getTestClasses(), getServices(), getProcessorOptions() ); this.compilationRequest = new CompilationRequest( getTestClasses(), getServices(), getProcessorOptions() );
} }
@ -202,8 +205,10 @@ abstract class CompilingStatement extends Statement {
assertDiagnostics( actualResult.getDiagnostics(), expectedResult.getDiagnostics() ); assertDiagnostics( actualResult.getDiagnostics(), expectedResult.getDiagnostics() );
if ( runCheckstyle ) {
assertCheckstyleRules(); assertCheckstyleRules();
} }
}
private void assertCheckstyleRules() throws Exception { private void assertCheckstyleRules() throws Exception {
if ( sourceOutputDir != null ) { if ( sourceOutputDir != null ) {