### Eclipse Workspace Patch 1.0 #P org.eclipse.jdt.core Index: compiler/org/eclipse/jdt/internal/compiler/ast/TypeReference.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/TypeReference.java,v retrieving revision 1.41 diff -u -r1.41 TypeReference.java --- compiler/org/eclipse/jdt/internal/compiler/ast/TypeReference.java 27 Jun 2008 16:03:55 -0000 1.41 +++ compiler/org/eclipse/jdt/internal/compiler/ast/TypeReference.java 29 Oct 2009 18:21:07 -0000 @@ -166,8 +166,12 @@ return true; } +protected void reportDeprecatedType(TypeBinding type, Scope scope, int index) { + scope.problemReporter().deprecatedType(type, this, index); +} + protected void reportDeprecatedType(TypeBinding type, Scope scope) { - scope.problemReporter().deprecatedType(type, this); + scope.problemReporter().deprecatedType(type, this, Integer.MAX_VALUE); } protected void reportInvalidType(Scope scope) { Index: compiler/org/eclipse/jdt/internal/compiler/ast/QualifiedTypeReference.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/QualifiedTypeReference.java,v retrieving revision 1.48 diff -u -r1.48 QualifiedTypeReference.java --- compiler/org/eclipse/jdt/internal/compiler/ast/QualifiedTypeReference.java 27 Jun 2008 16:03:54 -0000 1.48 +++ compiler/org/eclipse/jdt/internal/compiler/ast/QualifiedTypeReference.java 29 Oct 2009 18:21:07 -0000 @@ -87,7 +87,7 @@ return null; } if (i < last && isTypeUseDeprecated(this.resolvedType, scope)) { - reportDeprecatedType(this.resolvedType, scope); + reportDeprecatedType(this.resolvedType, scope, i); } if (isClassScope) if (((ClassScope) scope).detectHierarchyCycle(this.resolvedType, this)) // must connect hierarchy to find inherited member types Index: compiler/org/eclipse/jdt/internal/compiler/ast/JavadocQualifiedTypeReference.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/JavadocQualifiedTypeReference.java,v retrieving revision 1.25 diff -u -r1.25 JavadocQualifiedTypeReference.java --- compiler/org/eclipse/jdt/internal/compiler/ast/JavadocQualifiedTypeReference.java 19 Aug 2009 14:57:16 -0000 1.25 +++ compiler/org/eclipse/jdt/internal/compiler/ast/JavadocQualifiedTypeReference.java 29 Oct 2009 18:21:06 -0000 @@ -57,7 +57,7 @@ return null; } if (isTypeUseDeprecated(type, scope)) - reportDeprecatedType(type, scope); + reportDeprecatedType(type, scope, Integer.MAX_VALUE); // https://bugs.eclipse.org/bugs/show_bug.cgi?id=209936 // raw convert all enclosing types when dealing with Javadoc references if (type.isGenericType() || type.isParameterizedType()) { @@ -68,6 +68,10 @@ protected void reportDeprecatedType(TypeBinding type, Scope scope) { scope.problemReporter().javadocDeprecatedType(type, this, scope.getDeclarationModifiers()); } + + protected void reportDeprecatedType(TypeBinding type, Scope scope, int index) { + scope.problemReporter().javadocDeprecatedType(type, this, scope.getDeclarationModifiers(), index); + } protected void reportInvalidType(Scope scope) { scope.problemReporter().javadocInvalidType(this, this.resolvedType, scope.getDeclarationModifiers()); Index: compiler/org/eclipse/jdt/internal/compiler/ast/SingleTypeReference.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/SingleTypeReference.java,v retrieving revision 1.32 diff -u -r1.32 SingleTypeReference.java --- compiler/org/eclipse/jdt/internal/compiler/ast/SingleTypeReference.java 27 Jun 2008 16:03:54 -0000 1.32 +++ compiler/org/eclipse/jdt/internal/compiler/ast/SingleTypeReference.java 29 Oct 2009 18:21:07 -0000 @@ -70,7 +70,7 @@ } } if (isTypeUseDeprecated(memberType, scope)) - scope.problemReporter().deprecatedType(memberType, this); + reportDeprecatedType(memberType, scope); memberType = scope.environment().convertToRawType(memberType, false /*do not force conversion of enclosing types*/); if (memberType.isRawType() && (this.bits & IgnoreRawTypeCheck) == 0 Index: compiler/org/eclipse/jdt/internal/compiler/ast/ParameterizedQualifiedTypeReference.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ParameterizedQualifiedTypeReference.java,v retrieving revision 1.55 diff -u -r1.55 ParameterizedQualifiedTypeReference.java --- compiler/org/eclipse/jdt/internal/compiler/ast/ParameterizedQualifiedTypeReference.java 28 Apr 2009 16:53:03 -0000 1.55 +++ compiler/org/eclipse/jdt/internal/compiler/ast/ParameterizedQualifiedTypeReference.java 29 Oct 2009 18:21:07 -0000 @@ -188,7 +188,7 @@ } else { if (typeIsConsistent && currentType.isStatic() && (qualifyingType.isParameterizedTypeWithActualArguments() || qualifyingType.isGenericType())) { - scope.problemReporter().staticMemberOfParameterizedType(this, scope.environment().createParameterizedType((ReferenceBinding)currentType.erasure(), null, qualifyingType)); + scope.problemReporter().staticMemberOfParameterizedType(this, scope.environment().createParameterizedType((ReferenceBinding)currentType.erasure(), null, qualifyingType), i); typeIsConsistent = false; } ReferenceBinding enclosingType = currentType.enclosingType(); @@ -245,7 +245,7 @@ } return this.resolvedType; } else if (argLength != typeVariables.length) { // check arity - scope.problemReporter().incorrectArityForParameterizedType(this, currentType, argTypes); + scope.problemReporter().incorrectArityForParameterizedType(this, currentType, argTypes, i); return null; } // check parameterizing non-static member type of raw type @@ -271,7 +271,7 @@ return null; if (currentOriginal.isGenericType()) { if (typeIsConsistent && qualifyingType != null && qualifyingType.isParameterizedType()) { - scope.problemReporter().parameterizedMemberTypeMissingArguments(this, scope.environment().createParameterizedType(currentOriginal, null, qualifyingType)); + scope.problemReporter().parameterizedMemberTypeMissingArguments(this, scope.environment().createParameterizedType(currentOriginal, null, qualifyingType), i); typeIsConsistent = false; } qualifyingType = scope.environment().createRawType(currentOriginal, qualifyingType); // raw type @@ -282,7 +282,7 @@ } } if (isTypeUseDeprecated(qualifyingType, scope)) - reportDeprecatedType(qualifyingType, scope); + reportDeprecatedType(qualifyingType, scope, i); this.resolvedType = qualifyingType; } // array type ? Index: compiler/org/eclipse/jdt/internal/compiler/problem/ProblemReporter.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/ProblemReporter.java,v retrieving revision 1.399 diff -u -r1.399 ProblemReporter.java --- compiler/org/eclipse/jdt/internal/compiler/problem/ProblemReporter.java 21 Oct 2009 16:19:38 -0000 1.399 +++ compiler/org/eclipse/jdt/internal/compiler/problem/ProblemReporter.java 29 Oct 2009 18:21:12 -0000 @@ -1369,6 +1369,11 @@ } } public void deprecatedType(TypeBinding type, ASTNode location) { + deprecatedType(type, location, Integer.MAX_VALUE); +} +// The argument 'index' makes sure that we demarcate partial types correctly while marking off +// a deprecated type in a qualified reference (see bug 292510) +public void deprecatedType(TypeBinding type, ASTNode location, int index) { if (location == null) return; // 1G828DN - no type ref for synthetic arguments int severity = computeSeverity(IProblem.UsingDeprecatedType); if (severity == ProblemSeverities.Ignore) return; @@ -1379,7 +1384,7 @@ new String[] {new String(type.shortReadableName())}, severity, location.sourceStart, - nodeSourceEnd(null, location)); + nodeSourceEnd(null, location, index)); } public void disallowedTargetForAnnotation(Annotation annotation) { this.handle( @@ -2651,6 +2656,9 @@ sourceEnd); } public void incorrectArityForParameterizedType(ASTNode location, TypeBinding type, TypeBinding[] argumentTypes) { + incorrectArityForParameterizedType(location, type, argumentTypes, Integer.MAX_VALUE); +} +public void incorrectArityForParameterizedType(ASTNode location, TypeBinding type, TypeBinding[] argumentTypes, int index) { if (location == null) { this.handle( IProblem.IncorrectArityForParameterizedType, @@ -2666,7 +2674,7 @@ new String[] {new String(type.readableName()), typesAsString(false, argumentTypes, false)}, new String[] {new String(type.shortReadableName()), typesAsString(false, argumentTypes, true)}, location.sourceStart, - location.sourceEnd); + nodeSourceEnd(null, location, index)); } public void incorrectLocationForNonEmptyDimension(ArrayAllocationExpression expression, int index) { this.handle( @@ -3982,6 +3990,9 @@ } } public void javadocDeprecatedType(TypeBinding type, ASTNode location, int modifiers) { + javadocDeprecatedType(type, location, modifiers, Integer.MAX_VALUE); +} +public void javadocDeprecatedType(TypeBinding type, ASTNode location, int modifiers, int index) { if (location == null) return; // 1G828DN - no type ref for synthetic arguments int severity = computeSeverity(IProblem.JavadocUsingDeprecatedType); if (severity == ProblemSeverities.Ignore) return; @@ -3995,7 +4006,7 @@ new String[] {new String(type.shortReadableName())}, severity, location.sourceStart, - location.sourceEnd); + nodeSourceEnd(null, location, index)); } } } @@ -5227,7 +5238,11 @@ if (index == 0) { return (int) (ref.sourcePositions[ref.indexOfFirstFieldBinding-1]); } else { - return (int) (ref.sourcePositions[index]); + int length = ref.sourcePositions.length; + if (index < length) { + return (int) (ref.sourcePositions[index]); + } + return (int) (ref.sourcePositions[0]); } } FieldBinding[] otherFields = ref.otherBindings; @@ -5254,7 +5269,16 @@ } else if (node instanceof ArrayQualifiedTypeReference) { ArrayQualifiedTypeReference reference = (ArrayQualifiedTypeReference) node; int length = reference.sourcePositions.length; + if (index < length) { + return (int) reference.sourcePositions[index]; + } return (int) reference.sourcePositions[length - 1]; + } else if (node instanceof QualifiedTypeReference) { + QualifiedTypeReference reference = (QualifiedTypeReference) node; + int length = reference.sourcePositions.length; + if (index < length) { + return (int) reference.sourcePositions[index]; + } } return node.sourceEnd; } @@ -5621,7 +5645,7 @@ } return nameBuffer.toString(); } -public void parameterizedMemberTypeMissingArguments(ASTNode location, TypeBinding type) { +public void parameterizedMemberTypeMissingArguments(ASTNode location, TypeBinding type, int index) { if (location == null) { // binary case this.handle( IProblem.MissingArgumentsForParameterizedMemberType, @@ -5637,7 +5661,7 @@ new String[] {new String(type.readableName())}, new String[] {new String(type.shortReadableName())}, location.sourceStart, - location.sourceEnd); + nodeSourceEnd(null, location, index)); } public void parseError( int startPosition, @@ -5968,7 +5992,7 @@ new String[] {new String(type.readableName()), new String(type.erasure().readableName()), }, new String[] {new String(type.shortReadableName()),new String(type.erasure().shortReadableName()),}, location.sourceStart, - nodeSourceEnd(null, location)); + nodeSourceEnd(null, location, Integer.MAX_VALUE)); } public void recursiveConstructorInvocation(ExplicitConstructorCall constructorCall) { this.handle( @@ -6270,7 +6294,7 @@ type.sourceStart(), type.sourceEnd()); } -public void staticMemberOfParameterizedType(ASTNode location, ReferenceBinding type) { +public void staticMemberOfParameterizedType(ASTNode location, ReferenceBinding type, int index) { if (location == null) { // binary case this.handle( IProblem.StaticMemberOfParameterizedType, @@ -6281,7 +6305,6 @@ 0); return; } - int end = location.sourceEnd; /*if (location instanceof ArrayTypeReference) { ArrayTypeReference arrayTypeReference = (ArrayTypeReference) location; if (arrayTypeReference.token != null && arrayTypeReference.token.length == 0) return; @@ -6292,7 +6315,7 @@ new String[] {new String(type.readableName()), new String(type.enclosingType().readableName()), }, new String[] {new String(type.shortReadableName()), new String(type.enclosingType().shortReadableName()), }, location.sourceStart, - end); + nodeSourceEnd(null, location, index)); } public void stringConstantIsExceedingUtf8Limit(ASTNode location) { this.handle( #P org.eclipse.jdt.core.tests.compiler Index: src/org/eclipse/jdt/core/tests/compiler/regression/DeprecatedTest.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/DeprecatedTest.java,v retrieving revision 1.37 diff -u -r1.37 DeprecatedTest.java --- src/org/eclipse/jdt/core/tests/compiler/regression/DeprecatedTest.java 27 Jun 2008 16:04:44 -0000 1.37 +++ src/org/eclipse/jdt/core/tests/compiler/regression/DeprecatedTest.java 29 Oct 2009 18:21:20 -0000 @@ -593,7 +593,7 @@ "----------\n" + /* expected compiler log */ "1. ERROR in p\\M1.java (at line 4)\n" + " a.N1.N2.N3 m = null;\n" + - " ^^^^^^^^^^\n" + + " ^^^^^^^\n" + "The type N1.N2 is deprecated\n" + "----------\n" + "2. ERROR in p\\M1.java (at line 4)\n" + @@ -644,7 +644,7 @@ "----------\n" + /* expected compiler log */ "1. ERROR in p\\M1.java (at line 4)\n" + " a.N1.N2.N3 m = null;\n" + - " ^^^^^^^^^^\n" + + " ^^^^^^^\n" + "The type N1.N2 is deprecated\n" + "----------\n" + "2. ERROR in p\\M1.java (at line 4)\n" + @@ -739,7 +739,7 @@ "----------\n" + /* expected compiler log */ "1. ERROR in p\\M1.java (at line 4)\n" + " a.N1.N2.N3 m = null;\n" + - " ^^^^^^^^^^\n" + + " ^^^^^^^\n" + "The type N1.N2 is deprecated\n" + "----------\n" + "2. ERROR in p\\M1.java (at line 4)\n" + Index: src/org/eclipse/jdt/core/tests/compiler/regression/Deprecated15Test.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/Deprecated15Test.java,v retrieving revision 1.9 diff -u -r1.9 Deprecated15Test.java --- src/org/eclipse/jdt/core/tests/compiler/regression/Deprecated15Test.java 27 Jun 2008 16:04:44 -0000 1.9 +++ src/org/eclipse/jdt/core/tests/compiler/regression/Deprecated15Test.java 29 Oct 2009 18:21:20 -0000 @@ -137,7 +137,7 @@ "----------\n" + "1. ERROR in p\\M1.java (at line 4)\n" + " a.N1.N2.N3 m = null;\n" + - " ^^^^^^^^^^\n" + + " ^^^^^^^\n" + "The type N1.N2 is deprecated\n" + "----------\n" + "2. ERROR in p\\M1.java (at line 4)\n" + Index: src/org/eclipse/jdt/core/tests/compiler/regression/GenericTypeTest.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/GenericTypeTest.java,v retrieving revision 1.807 diff -u -r1.807 GenericTypeTest.java --- src/org/eclipse/jdt/core/tests/compiler/regression/GenericTypeTest.java 15 Oct 2009 18:57:45 -0000 1.807 +++ src/org/eclipse/jdt/core/tests/compiler/regression/GenericTypeTest.java 29 Oct 2009 18:21:45 -0000 @@ -8520,7 +8520,7 @@ "----------\n" + "1. ERROR in X.java (at line 11)\n" + " X.A.B bs;\n" + - " ^^^^^^^^^^^^^\n" + + " ^^^^^^^^^^^\n" + "The member type X.A must be parameterized, since it is qualified with a parameterized type\n" + "----------\n"); } @@ -8545,7 +8545,7 @@ "----------\n" + "1. ERROR in X.java (at line 11)\n" + " X.A.B bs;\n" + - " ^^^^^^^^^^^^^\n" + + " ^^^^^^^^^^^\n" + "The member type X.A cannot be qualified with a parameterized type, since it is static. Remove arguments from qualifying type X\n" + "----------\n"); } @@ -23948,7 +23948,7 @@ "----------\n" + "1. ERROR in X.java (at line 4)\n" + " X.B[] b = new X.B[1];\n" + - " ^^^^^^^^\n" + + " ^^^^^^\n" + "The member type X.B cannot be qualified with a parameterized type, since it is static. Remove arguments from qualifying type X\n" + "----------\n" + "2. ERROR in X.java (at line 4)\n" + @@ -45991,7 +45991,7 @@ "----------\n" + "1. WARNING in X.java (at line 2)\n" + " DeprecatedType.Member m1; // DeprecatedType and Member are raw + indirect access to Member\n" + - " ^^^^^^^^^^^^^^^^^^^^^\n" + + " ^^^^^^^^^^^^^^\n" + "The type DeprecatedType is deprecated\n" + "----------\n" + "2. WARNING in X.java (at line 2)\n" + @@ -49884,4 +49884,32 @@ "" ); } +// Test to verify that partial types in a parameterized qualified reference are +// demarcated correctly while annotating an arity problem in case of wrong number of arguments. +// Related to https://bugs.eclipse.org/bugs/show_bug.cgi?id=292510 +public void test1457() { + this.runNegativeTest( + new String[] { + "test/X.java", + "package test;\n" + + "// Valid Parameterized Type Declaration\n" + + "public class X {\n" + + " public class Y {\n" + + " public class Z {\n" + + " }\n" + + " }\n" + + "}\n" + + "// Invalid Valid Type Syntax (too many parameters)\n" + + "class Y {\n" + + " X.Y.Z x;\n" + + "}\n" + }, + "----------\n" + + "1. ERROR in test\\X.java (at line 11)\n" + + " X.Y.Z x;\n" + + " ^^^^^^^^^^^^^^^^^^^\n" + + "Incorrect number of arguments for type X.Y; it cannot be parameterized with arguments \n" + + "----------\n" + ); +} } \ No newline at end of file Index: src/org/eclipse/jdt/core/tests/compiler/regression/JavadocBugsTest.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/JavadocBugsTest.java,v retrieving revision 1.66 diff -u -r1.66 JavadocBugsTest.java --- src/org/eclipse/jdt/core/tests/compiler/regression/JavadocBugsTest.java 11 Sep 2009 18:34:58 -0000 1.66 +++ src/org/eclipse/jdt/core/tests/compiler/regression/JavadocBugsTest.java 29 Oct 2009 18:21:51 -0000 @@ -8586,5 +8586,49 @@ "}\n" }); } +// https://bugs.eclipse.org/bugs/show_bug.cgi?id=292510 +// Test to verify that partial types are demarcated correctly while +// annotating a deprecated type error in javadoc. +public void testBug292510() { + Map options = getCompilerOptions(); + options.put(CompilerOptions.OPTION_ReportDeprecationInDeprecatedCode, CompilerOptions.ENABLED); + runNegativeTest( + true, + new String[] { + "X.java", + "/** @deprecated */\n" + + "public class X {\n" + + " public class XX {\n" + + " public class XXX {\n" + + " }\n" + + " }\n" + + "}\n", + "Y.java", + "/**\n" + + " * @see X.XX.XXX\n" + + " */\n" + + "public class Y {\n" + + "}\n"}, + null, + options, + "----------\n" + + "1. ERROR in Y.java (at line 2)\n" + + " * @see X.XX.XXX\n" + + " ^\n" + + "Javadoc: The type X is deprecated\n" + + "----------\n" + + "2. ERROR in Y.java (at line 2)\n" + + " * @see X.XX.XXX\n" + + " ^^^^\n" + + "Javadoc: The type X.XX is deprecated\n" + + "----------\n" + + "3. ERROR in Y.java (at line 2)\n" + + " * @see X.XX.XXX\n" + + " ^^^^^^^^\n" + + "Javadoc: The type X.XX.XXX is deprecated\n" + + "----------\n", + JavacTestOptions.Excuse.EclipseWarningConfiguredAsError + ); +} } \ No newline at end of file Index: src/org/eclipse/jdt/core/tests/compiler/regression/InnerEmulationTest.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/InnerEmulationTest.java,v retrieving revision 1.54 diff -u -r1.54 InnerEmulationTest.java --- src/org/eclipse/jdt/core/tests/compiler/regression/InnerEmulationTest.java 16 Oct 2009 11:29:50 -0000 1.54 +++ src/org/eclipse/jdt/core/tests/compiler/regression/InnerEmulationTest.java 29 Oct 2009 18:21:48 -0000 @@ -5485,12 +5485,12 @@ "----------\n" + "2. WARNING in p\\X.java (at line 6)\n" + " A.M2.MM1 mm1 = (A.M2.MM1) o;\n" + - " ^^^^^^^^\n" + + " ^\n" + "The type A is deprecated\n" + "----------\n" + "3. WARNING in p\\X.java (at line 6)\n" + " A.M2.MM1 mm1 = (A.M2.MM1) o;\n" + - " ^^^^^^^^\n" + + " ^^^^\n" + "The type A.M2 is deprecated\n" + "----------\n" + "4. WARNING in p\\X.java (at line 6)\n" + @@ -5500,12 +5500,12 @@ "----------\n" + "5. WARNING in p\\X.java (at line 6)\n" + " A.M2.MM1 mm1 = (A.M2.MM1) o;\n" + - " ^^^^^^^^\n" + + " ^\n" + "The type A is deprecated\n" + "----------\n" + "6. WARNING in p\\X.java (at line 6)\n" + " A.M2.MM1 mm1 = (A.M2.MM1) o;\n" + - " ^^^^^^^^\n" + + " ^^^^\n" + "The type A.M2 is deprecated\n" + "----------\n" + "7. WARNING in p\\X.java (at line 6)\n" + @@ -5515,12 +5515,12 @@ "----------\n" + "8. WARNING in p\\X.java (at line 7)\n" + " A.M2.MM1[] mm1s = (A.M2.MM1[]) os;\n" + - " ^^^^^^^^\n" + + " ^\n" + "The type A is deprecated\n" + "----------\n" + "9. WARNING in p\\X.java (at line 7)\n" + " A.M2.MM1[] mm1s = (A.M2.MM1[]) os;\n" + - " ^^^^^^^^\n" + + " ^^^^\n" + "The type A.M2 is deprecated\n" + "----------\n" + "10. WARNING in p\\X.java (at line 7)\n" + @@ -5530,12 +5530,12 @@ "----------\n" + "11. WARNING in p\\X.java (at line 7)\n" + " A.M2.MM1[] mm1s = (A.M2.MM1[]) os;\n" + - " ^^^^^^^^\n" + + " ^\n" + "The type A is deprecated\n" + "----------\n" + "12. WARNING in p\\X.java (at line 7)\n" + " A.M2.MM1[] mm1s = (A.M2.MM1[]) os;\n" + - " ^^^^^^^^\n" + + " ^^^^\n" + "The type A.M2 is deprecated\n" + "----------\n" + "13. WARNING in p\\X.java (at line 7)\n" +