### Eclipse Workspace Patch 1.0 #P org.eclipse.jdt.core Index: dom/org/eclipse/jdt/core/dom/ASTConverter.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ASTConverter.java,v retrieving revision 1.272 diff -u -r1.272 ASTConverter.java --- dom/org/eclipse/jdt/core/dom/ASTConverter.java 15 Nov 2010 19:21:40 -0000 1.272 +++ dom/org/eclipse/jdt/core/dom/ASTConverter.java 8 Dec 2010 20:39:24 -0000 @@ -122,7 +122,10 @@ } } - protected void buildBodyDeclarations(org.eclipse.jdt.internal.compiler.ast.TypeDeclaration typeDeclaration, AbstractTypeDeclaration typeDecl) { + protected void buildBodyDeclarations( + org.eclipse.jdt.internal.compiler.ast.TypeDeclaration typeDeclaration, + AbstractTypeDeclaration typeDecl, + boolean isInterface) { // add body declaration in the lexical order org.eclipse.jdt.internal.compiler.ast.TypeDeclaration[] members = typeDeclaration.memberTypes; org.eclipse.jdt.internal.compiler.ast.FieldDeclaration[] fields = typeDeclaration.fields; @@ -177,7 +180,7 @@ case 1 : methodsIndex++; if (!nextMethodDeclaration.isDefaultConstructor() && !nextMethodDeclaration.isClinit()) { - typeDecl.bodyDeclarations().add(convert(nextMethodDeclaration)); + typeDecl.bodyDeclarations().add(convert(isInterface, nextMethodDeclaration)); } break; case 2 : @@ -249,7 +252,7 @@ case 1 : methodsIndex++; if (!nextMethodDeclaration.isDefaultConstructor() && !nextMethodDeclaration.isClinit()) { - enumDeclaration.bodyDeclarations().add(convert(nextMethodDeclaration)); + enumDeclaration.bodyDeclarations().add(convert(false, nextMethodDeclaration)); } break; case 2 : @@ -316,7 +319,7 @@ case 1 : methodsIndex++; if (!nextMethodDeclaration.isDefaultConstructor() && !nextMethodDeclaration.isClinit()) { - anonymousClassDeclaration.bodyDeclarations().add(convert(nextMethodDeclaration)); + anonymousClassDeclaration.bodyDeclarations().add(convert(false, nextMethodDeclaration)); } break; case 2 : @@ -415,7 +418,7 @@ } } - public ASTNode convert(org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration methodDeclaration) { + public ASTNode convert(boolean isInterface, org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration methodDeclaration) { checkCanceled(); if (methodDeclaration instanceof org.eclipse.jdt.internal.compiler.ast.AnnotationMethodDeclaration) { return convert((org.eclipse.jdt.internal.compiler.ast.AnnotationMethodDeclaration) methodDeclaration); @@ -457,6 +460,10 @@ } org.eclipse.jdt.internal.compiler.ast.ExplicitConstructorCall explicitConstructorCall = null; if (isConstructor) { + if (isInterface) { + // interface cannot have a constructor + methodDecl.setFlags(methodDecl.getFlags() | ASTNode.MALFORMED); + } org.eclipse.jdt.internal.compiler.ast.ConstructorDeclaration constructorDeclaration = (org.eclipse.jdt.internal.compiler.ast.ConstructorDeclaration) methodDeclaration; explicitConstructorCall = constructorDeclaration.constructorCall; switch(this.ast.apiLevel) { @@ -481,19 +488,20 @@ methodDecl.setExtraDimensions(extraDimensions); setTypeForMethodDeclaration(methodDecl, returnType, extraDimensions); } else { + // no return type for a method that is not a constructor + methodDecl.setFlags(methodDecl.getFlags() | ASTNode.MALFORMED); switch(this.ast.apiLevel) { - case AST.JLS2_INTERNAL : - methodDecl.setFlags(methodDecl.getFlags() | ASTNode.MALFORMED); - break; case AST.JLS3 : methodDecl.setReturnType2(null); } } } int declarationSourceStart = methodDeclaration.declarationSourceStart; - int declarationSourceEnd = methodDeclaration.bodyEnd; - methodDecl.setSourceRange(declarationSourceStart, declarationSourceEnd - declarationSourceStart + 1); - int closingPosition = retrieveRightBraceOrSemiColonPosition(methodDeclaration.bodyEnd + 1, methodDeclaration.declarationSourceEnd); + int bodyEnd = methodDeclaration.bodyEnd; + methodDecl.setSourceRange(declarationSourceStart, bodyEnd - declarationSourceStart + 1); + int declarationSourceEnd = methodDeclaration.declarationSourceEnd; + int rightBraceOrSemiColonPositionStart = bodyEnd == declarationSourceEnd ? bodyEnd : bodyEnd + 1; + int closingPosition = retrieveRightBraceOrSemiColonPosition(rightBraceOrSemiColonPositionStart, declarationSourceEnd); if (closingPosition != -1) { int startPosition = methodDecl.getStartPosition(); methodDecl.setSourceRange(startPosition, closingPosition - startPosition + 1); @@ -502,7 +510,7 @@ start = retrieveStartBlockPosition(methodHeaderEnd, methodDeclaration.bodyStart); if (start == -1) start = methodDeclaration.bodyStart; // use recovery position for body start - end = retrieveRightBrace(methodDeclaration.bodyEnd, methodDeclaration.declarationSourceEnd); + end = retrieveRightBrace(methodDeclaration.bodyEnd, declarationSourceEnd); Block block = null; if (start != -1 && end != -1) { /* @@ -528,14 +536,17 @@ } } } - if (block != null && (Modifier.isAbstract(methodDecl.getModifiers()) || Modifier.isNative(methodDecl.getModifiers()))) { + if (block != null + && (Modifier.isAbstract(methodDecl.getModifiers()) + || Modifier.isNative(methodDecl.getModifiers()) + || isInterface)) { methodDecl.setFlags(methodDecl.getFlags() | ASTNode.MALFORMED); } } else { // syntax error in this method declaration methodDecl.setFlags(methodDecl.getFlags() | ASTNode.MALFORMED); if (!methodDeclaration.isNative() && !methodDeclaration.isAbstract()) { - start = retrieveStartBlockPosition(methodHeaderEnd, declarationSourceEnd); + start = retrieveStartBlockPosition(methodHeaderEnd, bodyEnd); if (start == -1) start = methodDeclaration.bodyStart; // use recovery position for body start end = methodDeclaration.bodyEnd; // try to get the best end position @@ -708,7 +719,7 @@ typeDecl.setName(typeName); typeDecl.setSourceRange(typeDeclaration.declarationSourceStart, typeDeclaration.bodyEnd - typeDeclaration.declarationSourceStart + 1); - buildBodyDeclarations(typeDeclaration, typeDecl); + buildBodyDeclarations(typeDeclaration, typeDecl, false); // The javadoc comment is now got from list store in compilation unit declaration if (this.resolveBindings) { recordNodes(typeDecl, typeDeclaration); @@ -970,7 +981,7 @@ } else if(node instanceof org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration) { AbstractMethodDeclaration nextMethodDeclaration = (AbstractMethodDeclaration) node; if (!nextMethodDeclaration.isDefaultConstructor() && !nextMethodDeclaration.isClinit()) { - typeDecl.bodyDeclarations().add(convert(nextMethodDeclaration)); + typeDecl.bodyDeclarations().add(convert(false, nextMethodDeclaration)); } } else if(node instanceof org.eclipse.jdt.internal.compiler.ast.TypeDeclaration) { org.eclipse.jdt.internal.compiler.ast.TypeDeclaration nextMemberDeclaration = (org.eclipse.jdt.internal.compiler.ast.TypeDeclaration) node; @@ -2662,7 +2673,8 @@ if (typeDeclaration.modifiersSourceStart != -1) { setModifiers(typeDecl, typeDeclaration); } - typeDecl.setInterface(kind == org.eclipse.jdt.internal.compiler.ast.TypeDeclaration.INTERFACE_DECL); + boolean isInterface = kind == org.eclipse.jdt.internal.compiler.ast.TypeDeclaration.INTERFACE_DECL; + typeDecl.setInterface(isInterface); final SimpleName typeName = new SimpleName(this.ast); typeName.internalSetIdentifier(new String(typeDeclaration.name)); typeName.setSourceRange(typeDeclaration.sourceStart, typeDeclaration.sourceEnd - typeDeclaration.sourceStart + 1); @@ -2708,7 +2720,7 @@ } } } - buildBodyDeclarations(typeDeclaration, typeDecl); + buildBodyDeclarations(typeDeclaration, typeDecl, isInterface); if (this.resolveBindings) { recordNodes(typeDecl, typeDeclaration); recordNodes(typeName, typeDeclaration); #P org.eclipse.jdt.core.tests.model Index: src/org/eclipse/jdt/core/tests/dom/ASTConverter15Test.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/dom/ASTConverter15Test.java,v retrieving revision 1.298 diff -u -r1.298 ASTConverter15Test.java --- src/org/eclipse/jdt/core/tests/dom/ASTConverter15Test.java 2 Nov 2010 16:14:02 -0000 1.298 +++ src/org/eclipse/jdt/core/tests/dom/ASTConverter15Test.java 8 Dec 2010 20:39:25 -0000 @@ -3967,7 +3967,7 @@ Statement statement = (Statement) statements.get(0); assertEquals("Not a constructor invocation", ASTNode.CONSTRUCTOR_INVOCATION, statement.getNodeType()); ConstructorInvocation constructorInvocation = (ConstructorInvocation) statement; - checkSourceRange(constructorInvocation, "x. this();", source); + checkSourceRange(constructorInvocation, "x. this();", source, true/*expectMalformed*/); assertTrue("Node is not malformed", isMalformed(constructorInvocation)); } Index: src/org/eclipse/jdt/core/tests/dom/ASTConverterAST3Test.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/dom/ASTConverterAST3Test.java,v retrieving revision 1.29 diff -u -r1.29 ASTConverterAST3Test.java --- src/org/eclipse/jdt/core/tests/dom/ASTConverterAST3Test.java 18 Jan 2010 12:53:41 -0000 1.29 +++ src/org/eclipse/jdt/core/tests/dom/ASTConverterAST3Test.java 8 Dec 2010 20:39:25 -0000 @@ -6943,7 +6943,7 @@ "public void fails() {\n" + //$NON-NLS-1$ " foo()\n" + //$NON-NLS-1$ " }"; //$NON-NLS-1$ - checkSourceRange(methodDeclaration, expectedSource, source); + checkSourceRange(methodDeclaration, expectedSource, source, true/*expectMalformed*/); Block block = methodDeclaration.getBody(); expectedSource = "{\n" + //$NON-NLS-1$ @@ -6999,7 +6999,7 @@ "public void fails() {\n" + //$NON-NLS-1$ " foo()\n" + //$NON-NLS-1$ " }"; //$NON-NLS-1$ - checkSourceRange(methodDeclaration, expectedSource, source); + checkSourceRange(methodDeclaration, expectedSource, source, true/*expectMalformed*/); Block block = methodDeclaration.getBody(); expectedSource = "{\n" + //$NON-NLS-1$ @@ -8182,7 +8182,7 @@ " z\n" + //$NON-NLS-1$ " }\n" + //$NON-NLS-1$ "}"; //$NON-NLS-1$ - checkSourceRange(node, expectedSource, source); + checkSourceRange(node, expectedSource, source, true/*expectMalformed*/); int methodEndPosition = node.getStartPosition() + node.getLength(); node = getASTNode(compilationUnit, 0); assertNotNull("not null", node); //$NON-NLS-1$ Index: src/org/eclipse/jdt/core/tests/dom/ASTConverterTest.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/dom/ASTConverterTest.java,v retrieving revision 1.87 diff -u -r1.87 ASTConverterTest.java --- src/org/eclipse/jdt/core/tests/dom/ASTConverterTest.java 18 Jan 2010 12:53:41 -0000 1.87 +++ src/org/eclipse/jdt/core/tests/dom/ASTConverterTest.java 8 Dec 2010 20:39:26 -0000 @@ -35,7 +35,7 @@ } static { -// TESTS_NUMBERS = new int[] { 305 }; +// TESTS_NUMBERS = new int[] { 339 }; } public static Test suite() { return buildModelTestSuite(ASTConverterTest.class); @@ -7116,7 +7116,7 @@ "public void fails() {\n" + //$NON-NLS-1$ " foo()\n" + //$NON-NLS-1$ " }"; //$NON-NLS-1$ - checkSourceRange(methodDeclaration, expectedSource, source); + checkSourceRange(methodDeclaration, expectedSource, source, true/*expectMalformed*/); Block block = methodDeclaration.getBody(); expectedSource = "{\n" + //$NON-NLS-1$ @@ -7171,7 +7171,7 @@ "public void fails() {\n" + //$NON-NLS-1$ " foo()\n" + //$NON-NLS-1$ " }"; //$NON-NLS-1$ - checkSourceRange(methodDeclaration, expectedSource, source); + checkSourceRange(methodDeclaration, expectedSource, source, true/*expectMalformed*/); Block block = methodDeclaration.getBody(); expectedSource = "{\n" + //$NON-NLS-1$ @@ -8350,7 +8350,7 @@ " z\n" + //$NON-NLS-1$ " }\n" + //$NON-NLS-1$ "}"; //$NON-NLS-1$ - checkSourceRange(node, expectedSource, source); + checkSourceRange(node, expectedSource, source, true /*expectMalformed*/); int methodEndPosition = node.getStartPosition() + node.getLength(); node = getASTNode(compilationUnit, 0); assertNotNull("not null", node); //$NON-NLS-1$ Index: src/org/eclipse/jdt/core/tests/dom/ASTConverterTest2.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/dom/ASTConverterTest2.java,v retrieving revision 1.198 diff -u -r1.198 ASTConverterTest2.java --- src/org/eclipse/jdt/core/tests/dom/ASTConverterTest2.java 26 Oct 2010 17:24:12 -0000 1.198 +++ src/org/eclipse/jdt/core/tests/dom/ASTConverterTest2.java 8 Dec 2010 20:39:26 -0000 @@ -1908,7 +1908,7 @@ assertTrue("not a method declaration", node.getNodeType() == ASTNode.METHOD_DECLARATION); //$NON-NLS-1$ MethodDeclaration methodDeclaration = (MethodDeclaration) node; assertTrue("Is a constructor", !methodDeclaration.isConstructor()); - checkSourceRange(methodDeclaration, "private void foo(){", source); + checkSourceRange(methodDeclaration, "private void foo(){", source, true/*expectMalformed*/); node = getASTNode(compilationUnit, 0, 1); assertNotNull("No node", node); assertTrue("not a method declaration", node.getNodeType() == ASTNode.METHOD_DECLARATION); //$NON-NLS-1$ @@ -3125,7 +3125,7 @@ assertTrue("Not a constructor declaration", node.getNodeType() == ASTNode.METHOD_DECLARATION); //$NON-NLS-1$ MethodDeclaration declaration = (MethodDeclaration) node; assertTrue("A constructor", !declaration.isConstructor()); - checkSourceRange(declaration, "public method(final int parameter);", source); + checkSourceRange(declaration, "public method(final int parameter);", source, true/*expectMalformed*/); } /** @@ -3143,7 +3143,7 @@ assertTrue("Not a constructor declaration", node.getNodeType() == ASTNode.METHOD_DECLARATION); //$NON-NLS-1$ MethodDeclaration declaration = (MethodDeclaration) node; assertTrue("A constructor", !declaration.isConstructor()); - checkSourceRange(declaration, "public method(final int parameter) { }", source); + checkSourceRange(declaration, "public method(final int parameter) { }", source, true/*expectMalformed*/); } /** @@ -3280,7 +3280,7 @@ assertTrue("Not a method declaration", node.getNodeType() == ASTNode.METHOD_DECLARATION); //$NON-NLS-1$ MethodDeclaration declaration = (MethodDeclaration) node; assertTrue("Not a constructor", declaration.isConstructor()); - checkSourceRange(declaration, "public A();", source); + checkSourceRange(declaration, "public A();", source, true /*expectMalformed*/); } /** Index: src/org/eclipse/jdt/core/tests/dom/ASTConverterTestAST3_2.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/dom/ASTConverterTestAST3_2.java,v retrieving revision 1.177 diff -u -r1.177 ASTConverterTestAST3_2.java --- src/org/eclipse/jdt/core/tests/dom/ASTConverterTestAST3_2.java 26 Oct 2010 17:24:11 -0000 1.177 +++ src/org/eclipse/jdt/core/tests/dom/ASTConverterTestAST3_2.java 8 Dec 2010 20:39:26 -0000 @@ -122,7 +122,7 @@ static { // TESTS_NAMES = new String[] {"test0602"}; // TESTS_RANGE = new int[] { 713, -1 }; -// TESTS_NUMBERS = new int[] { 719 }; +// TESTS_NUMBERS = new int[] { 504, 505, 512, 720 }; } public static Test suite() { return buildModelTestSuite(ASTConverterTestAST3_2.class); @@ -1988,7 +1988,7 @@ assertTrue("not a method declaration", node.getNodeType() == ASTNode.METHOD_DECLARATION); //$NON-NLS-1$ MethodDeclaration methodDeclaration = (MethodDeclaration) node; assertTrue("Is a constructor", !methodDeclaration.isConstructor()); - checkSourceRange(methodDeclaration, "private void foo(){", source); + checkSourceRange(methodDeclaration, "private void foo(){", source, true/*expectMalformed*/); node = getASTNode(compilationUnit, 0, 1); assertNotNull("No node", node); assertTrue("not a method declaration", node.getNodeType() == ASTNode.METHOD_DECLARATION); //$NON-NLS-1$ @@ -3203,7 +3203,7 @@ assertTrue("Not a constructor declaration", node.getNodeType() == ASTNode.METHOD_DECLARATION); //$NON-NLS-1$ MethodDeclaration declaration = (MethodDeclaration) node; assertTrue("A constructor", !declaration.isConstructor()); - checkSourceRange(declaration, "public method(final int parameter);", source); + checkSourceRange(declaration, "public method(final int parameter);", source, true/*expectMalformed*/); } /** @@ -3221,7 +3221,7 @@ assertTrue("Not a constructor declaration", node.getNodeType() == ASTNode.METHOD_DECLARATION); //$NON-NLS-1$ MethodDeclaration declaration = (MethodDeclaration) node; assertTrue("A constructor", !declaration.isConstructor()); - checkSourceRange(declaration, "public method(final int parameter) { }", source); + checkSourceRange(declaration, "public method(final int parameter) { }", source, true/*expectMalformed*/); } /** @@ -3358,7 +3358,7 @@ assertTrue("Not a method declaration", node.getNodeType() == ASTNode.METHOD_DECLARATION); //$NON-NLS-1$ MethodDeclaration declaration = (MethodDeclaration) node; assertTrue("Not a constructor", declaration.isConstructor()); - checkSourceRange(declaration, "public A();", source); + checkSourceRange(declaration, "public A();", source, true/*expectMalformed*/); } /** @@ -5493,7 +5493,7 @@ node = getASTNode(compilationUnit, 0, 0); assertEquals("wrong type", ASTNode.FIELD_DECLARATION, node.getNodeType()); FieldDeclaration fieldDeclaration = (FieldDeclaration) node; - checkSourceRange(fieldDeclaration, "d String[][]", source.toCharArray()); + checkSourceRange(fieldDeclaration, "d String[][]", source.toCharArray(), true/*expectMalformed*/); Type type = fieldDeclaration.getType(); assertTrue("Not a simple type", type.isSimpleType()); List fragments = fieldDeclaration.fragments(); @@ -7243,7 +7243,7 @@ List fragments = fieldDeclaration.fragments(); assertEquals("wrong size", 1, fragments.size()); VariableDeclarationFragment fragment = (VariableDeclarationFragment) fragments.get(0); - checkSourceRange(fragment, "s = {\"\",,,", source); + checkSourceRange(fragment, "s = {\"\",,,", source, true/*expectMalformed*/); assertTrue("Not initializer", fragment.getInitializer() == null); assertTrue("Not a malformed node", isMalformed(fragment)); } @@ -10556,4 +10556,21 @@ } } } + /** + * http://bugs.eclipse.org/bugs/show_bug.cgi?id=47396 + */ + public void test0720() throws JavaModelException { + ICompilationUnit sourceUnit = getCompilationUnit("Converter" , "src", "test0720", "A.java"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ + char[] source = sourceUnit.getSource().toCharArray(); + ASTNode result = runConversion(AST.JLS3, sourceUnit, true); + assertTrue("not a compilation unit", result.getNodeType() == ASTNode.COMPILATION_UNIT); //$NON-NLS-1$ + CompilationUnit unit = (CompilationUnit) result; + assertEquals("Wrong number of problems", 1, unit.getProblems().length); //$NON-NLS-1$ + ASTNode node = getASTNode(unit, 1, 0); + assertNotNull(node); + assertTrue("Not a constructor declaration", node.getNodeType() == ASTNode.METHOD_DECLARATION); //$NON-NLS-1$ + MethodDeclaration declaration = (MethodDeclaration) node; + assertTrue("A constructor", !declaration.isConstructor()); + checkSourceRange(declaration, "public void method(final int parameter) { }", source, true/*expectMalformed*/); + } } \ No newline at end of file Index: src/org/eclipse/jdt/core/tests/dom/ConverterTestSetup.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/dom/ConverterTestSetup.java,v retrieving revision 1.62 diff -u -r1.62 ConverterTestSetup.java --- src/org/eclipse/jdt/core/tests/dom/ConverterTestSetup.java 26 Aug 2009 22:56:37 -0000 1.62 +++ src/org/eclipse/jdt/core/tests/dom/ConverterTestSetup.java 8 Dec 2010 20:39:26 -0000 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2009 IBM Corporation and others. + * Copyright (c) 2000, 2010 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -559,6 +559,9 @@ } protected void checkSourceRange(ASTNode node, String expectedContents, char[] source) { + checkSourceRange(node, expectedContents, source, false); + } + protected void checkSourceRange(ASTNode node, String expectedContents, char[] source, boolean expectMalformed) { assertNotNull("The node is null", node); //$NON-NLS-1$ assertTrue("The node(" + node.getClass() + ").getLength() == 0", node.getLength() != 0); //$NON-NLS-1$ //$NON-NLS-2$ assertTrue("The node.getStartPosition() == -1", node.getStartPosition() != -1); //$NON-NLS-1$ @@ -568,6 +571,11 @@ System.arraycopy(source, start, actualContents, 0, length); String actualContentsString = new String(actualContents); assertSourceEquals("Unexpected source", Util.convertToIndependantLineDelimiter(expectedContents), Util.convertToIndependantLineDelimiter(actualContentsString)); + if (expectMalformed) { + assertTrue("Is not malformed", isMalformed(node)); + } else { + assertFalse("Is malformed", isMalformed(node)); + } } protected boolean isMalformed(ASTNode node) { Index: workspace/Converter/src/test0720/A.java =================================================================== RCS file: workspace/Converter/src/test0720/A.java diff -N workspace/Converter/src/test0720/A.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ workspace/Converter/src/test0720/A.java 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,14 @@ +package test0720; + +public class A +{ + public A() + { + + } + +} +interface B +{ + public void method(final int parameter) { } +} \ No newline at end of file