diff options
Diffstat (limited to 'org.eclipse.jdt.core/model/org/eclipse')
13 files changed, 152 insertions, 22 deletions
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IJavaModelStatusConstants.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IJavaModelStatusConstants.java index 505da26ba..1604a57d4 100644 --- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IJavaModelStatusConstants.java +++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IJavaModelStatusConstants.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2015 IBM Corporation and others. + * Copyright (c) 2000, 2018 IBM Corporation and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -375,4 +375,14 @@ public interface IJavaModelStatusConstants { */ public static final int TEST_OUTPUT_FOLDER_MUST_BE_SEPARATE_FROM_MAIN_OUTPUT_FOLDERS = 1016; + /** + * <p> + * Status constant indicating that the project has only main source folders but depends on a project that has only + * test source folders. + * </p> + * + * @since 3.16 + */ + public static final int MAIN_ONLY_PROJECT_DEPENDS_ON_TEST_ONLY_PROJECT = 1017; + } diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IPackageFragmentRoot.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IPackageFragmentRoot.java index 6b8f47281..20b09a0d6 100644 --- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IPackageFragmentRoot.java +++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IPackageFragmentRoot.java @@ -451,9 +451,9 @@ public interface IPackageFragmentRoot void move(IPath destination, int updateResourceFlags, int updateModelFlags, IClasspathEntry sibling, IProgressMonitor monitor) throws JavaModelException; /** - * Returns the <code>IModuleDescription</code> that this package fragment root contains - * or <code>null</code> if the root doesn't contain any named module. If present the module - * descriptor is found as a child of the package fragment representing the default package. + * Returns the <code>IModuleDescription</code> that this package fragment root contains. + * Returns <code>null</code> if the root doesn't contain any named module or if the project compiler compliance is 1.8 or lower. + * If present the module descriptor is found as a child of the package fragment representing the default package. * * Note that only one of the source package fragment roots in a Java Project can legally * contain a module descriptor. diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/JavaCore.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/JavaCore.java index fb4fb3a77..68bdc8255 100644 --- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/JavaCore.java +++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/JavaCore.java @@ -2579,6 +2579,21 @@ public final class JavaCore extends Plugin { * @since 3.6.4 */ public static final String CORE_OUTPUT_LOCATION_OVERLAPPING_ANOTHER_SOURCE = PLUGIN_ID + ".classpath.outputOverlappingAnotherSource"; //$NON-NLS-1$ + + /** + * Core option ID: Reporting if a project which has only main sources depends on a project with only test sources. + * <p> Indicate the severity of the problem reported when a project that has one or more main source folders but + * no test source folders has a project on its build path that only has one or more test source folders, but no main source folders.</p> + * + * <dl> + * <dt>Option id:</dt><dd><code>"org.eclipse.jdt.core.classpath.mainOnlyProjectHasTestOnlyDependency"</code></dd> + * <dt>Possible values:</dt><dd><code>{ "error", "ignore" }</code></dd> + * <dt>Default:</dt><dd><code>"error"</code></dd> + * </dl> + * @since 3.16 + */ + public static final String CORE_MAIN_ONLY_PROJECT_HAS_TEST_ONLY_DEPENDENCY = PLUGIN_ID + ".classpath.mainOnlyProjectHasTestOnlyDependency"; //$NON-NLS-1$ + /** * Core option ID: Set the timeout value for retrieving the method's parameter names from javadoc. * <p>Timeout in milliseconds to retrieve the method's parameter names from javadoc.</p> @@ -4285,6 +4300,37 @@ public final class JavaCore extends Plugin { } /** + * Returns the option that can be used to configure the severity of the + * compiler build path problem identified by <code>id</code> if any, + * <code>null</code> otherwise. Non-null return values are taken from the + * constants defined by this class whose names start with + * <code>CORE_</code> and for which the possible values of the + * option are defined by <code>{ "error", "warning", "info", "ignore" }</code>. A + * null return value means that the provided id is unknown or that + * it matches a problem whose severity cannot be configured. + * @param id one of the build path problems defined in IJavaModelStatusConstants + * @return the option that can be used to configure the severity of the + * compiler problem identified by <code>id</code> if any, + * <code>null</code> otherwise + * @since 3.16 + */ + public static String getOptionForConfigurableBuildPathProblemSeverity(int id) { + switch (id) { + case IJavaModelStatusConstants.CLASSPATH_CYCLE: + return JavaCore.CORE_CIRCULAR_CLASSPATH; + case IJavaModelStatusConstants.INCOMPATIBLE_JDK_LEVEL: + return JavaCore.CORE_INCOMPATIBLE_JDK_LEVEL; + case IJavaModelStatusConstants.OUTPUT_LOCATION_OVERLAPPING_ANOTHER_SOURCE: + return JavaCore.CORE_OUTPUT_LOCATION_OVERLAPPING_ANOTHER_SOURCE; + case IJavaModelStatusConstants.MAIN_ONLY_PROJECT_DEPENDS_ON_TEST_ONLY_PROJECT: + return JavaCore.CORE_MAIN_ONLY_PROJECT_HAS_TEST_ONLY_DEPENDENCY; + case IJavaModelStatusConstants.INVALID_CLASSPATH: + return JavaCore.CORE_INCOMPLETE_CLASSPATH; + } + return null; + } + + /** * Returns the table of the current options. Initially, all options have their default values, * and this method returns a table that includes all known options. * <p> diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/Annotation.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/Annotation.java index 277edc5fc..fd01fd524 100644 --- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/Annotation.java +++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/Annotation.java @@ -39,7 +39,7 @@ public class Annotation extends SourceRefElement implements IAnnotation { public Annotation(JavaElement parent, String name, String memberValuePairName) { super(parent); - this.name = name; + this.name = name.intern(); this.memberValuePairName = memberValuePairName; } diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ClasspathEntry.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ClasspathEntry.java index 428a0c4fc..284fb648f 100644 --- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ClasspathEntry.java +++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ClasspathEntry.java @@ -1870,11 +1870,10 @@ public class ClasspathEntry implements IClasspathEntry { } catch(JavaModelException e){ return e.getJavaModelStatus(); } - int length = classpath.length; int outputCount = 1; - IPath[] outputLocations = new IPath[length+1]; - boolean[] allowNestingInOutputLocations = new boolean[length+1]; + IPath[] outputLocations = new IPath[classpath.length+1]; + boolean[] allowNestingInOutputLocations = new boolean[classpath.length+1]; outputLocations[0] = projectOutputLocation; // retrieve and check output locations @@ -1964,8 +1963,7 @@ public class ClasspathEntry implements IClasspathEntry { } } - for (int i = 0 ; i < length; i++) { - IClasspathEntry resolvedEntry = classpath[i]; + for (IClasspathEntry resolvedEntry : classpath) { IPath path = resolvedEntry.getPath(); int index; switch(resolvedEntry.getEntryKind()){ @@ -1991,8 +1989,7 @@ public class ClasspathEntry implements IClasspathEntry { } // check all entries - for (int i = 0 ; i < length; i++) { - IClasspathEntry entry = classpath[i]; + for (IClasspathEntry entry : classpath) { if (entry == null) continue; IPath entryPath = entry.getPath(); int kind = entry.getEntryKind(); @@ -2010,8 +2007,7 @@ public class ClasspathEntry implements IClasspathEntry { // allow nesting source entries in each other as long as the outer entry excludes the inner one if (kind == IClasspathEntry.CPE_SOURCE || (kind == IClasspathEntry.CPE_LIBRARY && (JavaModel.getTarget(entryPath, false/*don't check existence*/) instanceof IContainer))) { - for (int j = 0; j < classpath.length; j++){ - IClasspathEntry otherEntry = classpath[j]; + for (IClasspathEntry otherEntry : classpath) { if (otherEntry == null) continue; int otherKind = otherEntry.getEntryKind(); IPath otherPath = otherEntry.getPath(); @@ -2071,8 +2067,7 @@ public class ClasspathEntry implements IClasspathEntry { // diagnose nesting source folder issue before this one, for example, [src]"Project/", [src]"Project/source/" and output="Project/" should // first complain about missing exclusion pattern IJavaModelStatus cachedStatus = null; - for (int i = 0 ; i < length; i++) { - IClasspathEntry entry = classpath[i]; + for (IClasspathEntry entry : classpath) { if (entry == null) continue; IPath entryPath = entry.getPath(); int kind = entry.getEntryKind(); @@ -2084,8 +2079,7 @@ public class ClasspathEntry implements IClasspathEntry { if (kind == IClasspathEntry.CPE_SOURCE) { IPath output = entry.getOutputLocation(); if (output == null) output = projectOutputLocation; // if no specific output, still need to check using default output (this line would check default output) - for (int j = 0; j < length; j++) { - IClasspathEntry otherEntry = classpath[j]; + for (IClasspathEntry otherEntry : classpath) { if (otherEntry == entry) continue; switch (otherEntry.getEntryKind()) { @@ -2126,6 +2120,42 @@ public class ClasspathEntry implements IClasspathEntry { } } + if (hasSource && testSourcesFolders.size() == 0 && !JavaCore.IGNORE.equals(javaProject.getOption(JavaCore.CORE_MAIN_ONLY_PROJECT_HAS_TEST_ONLY_DEPENDENCY, true))) { + for (IClasspathEntry entry : classpath) { + if (entry == null) + continue; + IPath entryPath = entry.getPath(); + if (entry.getEntryKind() == IClasspathEntry.CPE_PROJECT) { + if (entryPath.isAbsolute() && entryPath.segmentCount() == 1) { + IProject prereqProjectRsc = workspaceRoot.getProject(entryPath.segment(0)); + IJavaProject prereqProject = JavaCore.create(prereqProjectRsc); + boolean hasMain = false; + boolean hasTest = false; + try { + for (IClasspathEntry nested : prereqProject.getRawClasspath()) { + if (nested.getEntryKind() == IClasspathEntry.CPE_SOURCE) { + if (nested.isTest()) { + hasTest = true; + } else { + hasMain = true; + } + if (hasTest && hasMain) + break; + } + } + } catch (JavaModelException e) { + // is reported elsewhere + } + if (hasTest && !hasMain) { + return new JavaModelStatus(IJavaModelStatusConstants.MAIN_ONLY_PROJECT_DEPENDS_ON_TEST_ONLY_PROJECT, + Messages.bind(Messages.classpath_main_only_project_depends_on_test_only_project, + new String[] { prereqProject.getElementName() })); + } + } + } + } + } + // NOTE: The above code that checks for IJavaModelStatusConstants.OUTPUT_LOCATION_OVERLAPPING_ANOTHER_SOURCE, can be configured to return // a WARNING status and hence should be at the end of this validation method. Any other code that might return a more severe ERROR should be // inserted before the mentioned code. diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ExternalFoldersManager.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ExternalFoldersManager.java index 1fb75315a..9c13682bd 100644 --- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ExternalFoldersManager.java +++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ExternalFoldersManager.java @@ -57,6 +57,7 @@ import org.eclipse.jdt.internal.core.util.Messages; import org.eclipse.jdt.internal.core.util.Util; public class ExternalFoldersManager { + private static final boolean WINDOWS = System.getProperty("os.name").toLowerCase().contains("windows"); //$NON-NLS-1$//$NON-NLS-2$ private static final String EXTERNAL_PROJECT_NAME = ".org.eclipse.jdt.core.external.folders"; //$NON-NLS-1$ private static final String LINKED_FOLDER_NAME = ".link"; //$NON-NLS-1$ private Map<IPath, IFolder> folders; @@ -118,11 +119,12 @@ public class ExternalFoldersManager { if (externalPath == null || externalPath.isEmpty()) { return false; } + JavaModelManager manager = JavaModelManager.getJavaModelManager(); if (manager.isExternalFile(externalPath) || manager.isAssumedExternalFile(externalPath)) { return false; } - if (!externalPath.isAbsolute()) { + if (!externalPath.isAbsolute() || (WINDOWS && externalPath.getDevice() == null)) { // can be only project relative path return false; } @@ -142,12 +144,14 @@ public class ExternalFoldersManager { if (isInternalContainerPath(externalPath)) { return false; } + // From here on the legacy code assumes that not existing resource must be external. + // We just follow the old assumption. if (externalPath.getFileExtension() != null/*likely a .jar, .zip, .rar or other file*/) { manager.addAssumedExternalFile(externalPath); - // not existing external file + // assume not existing external (?) file (?) (can also be a folder with dotted name!) return false; } - // not existing external folder + // assume not existing external (?) folder (?) return true; } diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaCorePreferenceInitializer.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaCorePreferenceInitializer.java index dfebdb8d1..ed85f3b54 100644 --- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaCorePreferenceInitializer.java +++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaCorePreferenceInitializer.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2015 IBM Corporation and others. + * Copyright (c) 2000, 2018 IBM Corporation and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -79,6 +79,7 @@ public class JavaCorePreferenceInitializer extends AbstractPreferenceInitializer //{ObjectTeams: one more setting: defaultOptionsMap.put(JavaCore.AST_INCLUDES_ROLE_FILES, JavaCore.DISABLED); // SH} + defaultOptionsMap.put(JavaCore.CORE_MAIN_ONLY_PROJECT_HAS_TEST_ONLY_DEPENDENCY, JavaCore.ERROR); // encoding setting comes from resource plug-in optionNames.add(JavaCore.CORE_ENCODING); diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaModelManager.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaModelManager.java index 648cee83e..09250fcc7 100644 --- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaModelManager.java +++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaModelManager.java @@ -1708,6 +1708,7 @@ public class JavaModelManager implements ISaveParticipant, IContentTypeChangeLis propertyName.equals(JavaCore.CORE_INCOMPLETE_CLASSPATH) || propertyName.equals(JavaCore.CORE_CIRCULAR_CLASSPATH) || propertyName.equals(JavaCore.CORE_INCOMPATIBLE_JDK_LEVEL) || + propertyName.equals(JavaCore.CORE_MAIN_ONLY_PROJECT_HAS_TEST_ONLY_DEPENDENCY) || propertyName.equals(JavaCore.COMPILER_CODEGEN_TARGET_PLATFORM) || propertyName.equals(JavaCore.CORE_OUTPUT_LOCATION_OVERLAPPING_ANOTHER_SOURCE)) { JavaModelManager manager = JavaModelManager.getJavaModelManager(); @@ -2470,6 +2471,7 @@ public class JavaModelManager implements ISaveParticipant, IContentTypeChangeLis defaultOptionsMap.put(JavaCore.CORE_INCOMPLETE_CLASSPATH, JavaCore.ERROR); defaultOptionsMap.put(JavaCore.CORE_CIRCULAR_CLASSPATH, JavaCore.ERROR); defaultOptionsMap.put(JavaCore.CORE_INCOMPATIBLE_JDK_LEVEL, JavaCore.IGNORE); + defaultOptionsMap.put(JavaCore.CORE_MAIN_ONLY_PROJECT_HAS_TEST_ONLY_DEPENDENCY, JavaCore.ERROR); defaultOptionsMap.put(JavaCore.CORE_OUTPUT_LOCATION_OVERLAPPING_ANOTHER_SOURCE, JavaCore.ERROR); defaultOptionsMap.put(JavaCore.CORE_ENABLE_CLASSPATH_EXCLUSION_PATTERNS, JavaCore.ENABLED); defaultOptionsMap.put(JavaCore.CORE_ENABLE_CLASSPATH_MULTIPLE_OUTPUT_LOCATIONS, JavaCore.ENABLED); diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaProject.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaProject.java index c170620af..abe02ffe9 100644 --- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaProject.java +++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaProject.java @@ -1186,6 +1186,14 @@ public class JavaProject return; // setting == IGNORE } break; + case IJavaModelStatusConstants.MAIN_ONLY_PROJECT_DEPENDS_ON_TEST_ONLY_PROJECT: + setting = getOption(JavaCore.CORE_MAIN_ONLY_PROJECT_HAS_TEST_ONLY_DEPENDENCY, true); + if (JavaCore.ERROR.equals(setting)) { + severity = IMarker.SEVERITY_ERROR; + } else { + return; // setting == IGNORE + } + break; default: IPath path = status.getPath(); if (path != null) arguments = new String[] { path.toString() }; @@ -1945,6 +1953,7 @@ public class JavaProject propertyName.equals(JavaCore.CORE_CIRCULAR_CLASSPATH) || propertyName.equals(JavaCore.CORE_OUTPUT_LOCATION_OVERLAPPING_ANOTHER_SOURCE) || propertyName.equals(JavaCore.CORE_INCOMPATIBLE_JDK_LEVEL) || + propertyName.equals(JavaCore.CORE_MAIN_ONLY_PROJECT_HAS_TEST_ONLY_DEPENDENCY) || propertyName.equals(JavaCore.COMPILER_CODEGEN_TARGET_PLATFORM)) { manager.deltaState.addClasspathValidation(JavaProject.this); diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JrtPackageFragmentRoot.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JrtPackageFragmentRoot.java index 702e50730..cd3e8158c 100644 --- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JrtPackageFragmentRoot.java +++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JrtPackageFragmentRoot.java @@ -151,6 +151,11 @@ public class JrtPackageFragmentRoot extends JarPackageFragmentRoot implements IM } return null; } + + @Override + protected boolean isComplianceJava9OrHigher() { + return true; + } @Override public char[][] getModulesDeclaringPackage(String qualifiedPackageName, String requestedModuleName) { diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/PackageFragmentRoot.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/PackageFragmentRoot.java index 519c2c8e4..5d8f782c3 100644 --- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/PackageFragmentRoot.java +++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/PackageFragmentRoot.java @@ -22,7 +22,9 @@ import org.eclipse.core.resources.*; import org.eclipse.core.runtime.*; import org.eclipse.jdt.core.*; import org.eclipse.jdt.core.compiler.CharOperation; +import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; import org.eclipse.jdt.internal.compiler.env.AutomaticModuleNaming; +import org.eclipse.jdt.internal.compiler.impl.CompilerOptions; import org.eclipse.jdt.internal.compiler.lookup.TypeConstants; import org.eclipse.jdt.internal.core.util.MementoTokenizer; import org.eclipse.jdt.internal.core.util.Messages; @@ -884,6 +886,13 @@ public String getClassFilePath(String classname) { } @Override public IModuleDescription getModuleDescription() { + if (isComplianceJava9OrHigher()) { + return getSourceModuleDescription(); + } + return null; +} + +private IModuleDescription getSourceModuleDescription() { try { IJavaElement[] pkgs = getChildren(); for (int j = 0, length = pkgs.length; j < length; j++) { @@ -959,4 +968,16 @@ public boolean hasCompilationUnit(String qualifiedPackageName, String moduleName public Manifest getManifest() { return null; } + +protected boolean isComplianceJava9OrHigher() { + IJavaProject javaProject = getJavaProject(); + return isComplianceJava9OrHigher(javaProject); +} + +private static boolean isComplianceJava9OrHigher(IJavaProject javaProject) { + if (javaProject == null) { + return false; + } + return CompilerOptions.versionToJdkLevel(javaProject.getOption(JavaCore.COMPILER_COMPLIANCE, true)) >= ClassFileConstants.JDK9; +} } diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/Messages.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/Messages.java index 82e9c0243..f1fe4d648 100644 --- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/Messages.java +++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/Messages.java @@ -192,6 +192,7 @@ public final class Messages extends NLS { public static String classpath_invalidExternalAnnotationPath; public static String classpath_testSourceRequiresSeparateOutputFolder; public static String classpath_testOutputFolderMustBeSeparateFromMainOutputFolders; + public static String classpath_main_only_project_depends_on_test_only_project; public static String file_notFound; public static String file_badFormat; public static String path_nullPath; diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/messages.properties b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/messages.properties index 7d00a513b..305dbb823 100644 --- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/messages.properties +++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/messages.properties @@ -188,6 +188,7 @@ classpath_deprecated_variable = Classpath variable ''{0}'' in project ''{1}'' is classpath_invalidExternalAnnotationPath = Invalid external annotation path: ''{0}'' in project ''{1}'', for classpath entry ''{2}'' classpath_testSourceRequiresSeparateOutputFolder=Test source folder ''{0}'' in project ''{1}'' must have a separate output folder classpath_testOutputFolderMustBeSeparateFromMainOutputFolders=Test source folder ''{0}'' in project ''{1}'' must have an output folder that is not also used for main sources +classpath_main_only_project_depends_on_test_only_project=Project has only main sources but depends on project ''{0}'' which has only test sources. ### miscellaneous buffer_closed=Buffer is closed |