diff --git a/build/org.eclipse.cdt.make.core/src/org/eclipse/cdt/make/internal/core/scannerconfig2/DefaultRunSIProvider.java b/build/org.eclipse.cdt.make.core/src/org/eclipse/cdt/make/internal/core/scannerconfig2/DefaultRunSIProvider.java index 1b8d8b8d146..9d482eb606d 100644 --- a/build/org.eclipse.cdt.make.core/src/org/eclipse/cdt/make/internal/core/scannerconfig2/DefaultRunSIProvider.java +++ b/build/org.eclipse.cdt.make.core/src/org/eclipse/cdt/make/internal/core/scannerconfig2/DefaultRunSIProvider.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2004, 2010 IBM Corporation and others. + * Copyright (c) 2004, 2011 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 @@ -58,7 +58,6 @@ public class DefaultRunSIProvider implements IExternalScannerInfoProvider { private static final String EXTERNAL_SI_PROVIDER_ERROR = "ExternalScannerInfoProvider.Provider_Error"; //$NON-NLS-1$ private static final String GMAKE_ERROR_PARSER_ID = "org.eclipse.cdt.core.GmakeErrorParser"; //$NON-NLS-1$ private static final String PREF_CONSOLE_ENABLED = "org.eclipse.cdt.make.core.scanner.discovery.console.enabled"; //$NON-NLS-1$ - private static final String LANG_ENV_VAR = "LANG"; //$NON-NLS-1$ private static final String NEWLINE = System.getProperty("line.separator", "\n"); //$NON-NLS-1$ //$NON-NLS-2$ private static final String PATH_ENV = "PATH"; //$NON-NLS-1$ @@ -262,21 +261,19 @@ public class DefaultRunSIProvider implements IExternalScannerInfoProvider { private Properties getEnvMap(ICommandLauncher launcher, Properties initialEnv) { // Set the environmennt, some scripts may need the CWD var to be set. - Properties props = initialEnv != null ? initialEnv : launcher.getEnvironment(); - - if (fWorkingDirectory != null) { + Properties props = initialEnv != null ? initialEnv : launcher.getEnvironment(); + + if (fWorkingDirectory != null) { props.put("CWD", fWorkingDirectory.toOSString()); //$NON-NLS-1$ props.put("PWD", fWorkingDirectory.toOSString()); //$NON-NLS-1$ } - // On POSIX (Linux, UNIX) systems reset LANG variable to English with - // UTF-8 encoding - // since GNU compilers can handle only UTF-8 characters. English language is chosen - // beacuse GNU compilers inconsistently handle different locales when generating - // output of the 'gcc -v' command. Include paths with locale characters will be - // handled properly regardless of the language as long as the encoding is set to UTF-8. - if (props.containsKey(LANG_ENV_VAR)) { - props.put(LANG_ENV_VAR, "en_US.UTF-8"); //$NON-NLS-1$ - } + // On POSIX (Linux, UNIX) systems reset LANG variable to English with + // UTF-8 encoding since GNU compilers can handle only UTF-8 characters. + // Include paths with locale characters will be handled properly regardless + // of the language as long as the encoding is set to UTF-8. + // English language is chosen because parser relies on English messages + // in the output of the 'gcc -v' command. + props.put("LC_ALL", "en_US.UTF-8"); //$NON-NLS-1$ //$NON-NLS-2$ return props; } diff --git a/build/org.eclipse.cdt.make.core/src/org/eclipse/cdt/make/internal/core/scannerconfig2/GCCSpecsRunSIProvider.java b/build/org.eclipse.cdt.make.core/src/org/eclipse/cdt/make/internal/core/scannerconfig2/GCCSpecsRunSIProvider.java index bd15498025e..8ecb3e935e4 100644 --- a/build/org.eclipse.cdt.make.core/src/org/eclipse/cdt/make/internal/core/scannerconfig2/GCCSpecsRunSIProvider.java +++ b/build/org.eclipse.cdt.make.core/src/org/eclipse/cdt/make/internal/core/scannerconfig2/GCCSpecsRunSIProvider.java @@ -1,94 +1,93 @@ -/******************************************************************************* - * Copyright (c) 2004, 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 - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * IBM - Initial API and implementation - *******************************************************************************/ -package org.eclipse.cdt.make.internal.core.scannerconfig2; - -import java.util.List; - -import org.eclipse.cdt.core.CCProjectNature; -import org.eclipse.cdt.core.CProjectNature; -import org.eclipse.cdt.make.core.MakeCorePlugin; -import org.eclipse.cdt.make.core.scannerconfig.ScannerInfoTypes; -import org.eclipse.cdt.make.internal.core.scannerconfig.gnu.GCCScannerConfigUtil; -import org.eclipse.core.resources.IProject; -import org.eclipse.core.runtime.CoreException; - -/** - * Runs a command to retrieve compiler intrinsic scanner info from 'specs' file. - * - * @author vhirsl - */ -public class GCCSpecsRunSIProvider extends DefaultRunSIProvider { - - /* (non-Javadoc) - * @see org.eclipse.cdt.make.internal.core.scannerconfig2.DefaultRunSIProvider#initialize() - */ - @Override - protected boolean initialize() { - boolean rc = super.initialize(); - - if (rc) { - String targetFile = "dummy"; //$NON-NLS-1$ - IProject project = resource.getProject(); - try { - if (project.hasNature(CCProjectNature.CC_NATURE_ID)) { - targetFile = GCCScannerConfigUtil.CPP_SPECS_FILE; - } - else if (project.hasNature(CProjectNature.C_NATURE_ID)) { - targetFile = GCCScannerConfigUtil.C_SPECS_FILE; - } - // replace string variables in compile arguments - // TODO Vmir - use string variable replacement - for (int i = 0; i < fCompileArguments.length; ++i) { - fCompileArguments[i] = fCompileArguments[i].replaceAll("\\$\\{plugin_state_location\\}", //$NON-NLS-1$ - MakeCorePlugin.getWorkingDirectory().toString()); - fCompileArguments[i] = fCompileArguments[i].replaceAll("\\$\\{specs_file\\}", targetFile); //$NON-NLS-1$ - } - } catch (CoreException e) { - //TODO VMIR better error handling - MakeCorePlugin.log(e.getStatus()); - rc = false; - } - } - return rc; - } - - /* (non-Javadoc) - * @see org.eclipse.cdt.make.internal.core.scannerconfig2.DefaultRunSIProvider#prepareArguments(boolean) - */ - @Override - protected String[] prepareArguments(boolean isDefaultCommand) { - if (collector == null) - return fCompileArguments; - - @SuppressWarnings("unchecked") - List tso = collector.getCollectedScannerInfo(resource.getProject(), ScannerInfoTypes.TARGET_SPECIFIC_OPTION); - if (tso == null || tso.size() == 0) { - return fCompileArguments; - } - - String[] rv = null; - // commandArguments may have multiple arguments; tokenizing - int nTokens = 0; - if (fCompileArguments != null && fCompileArguments.length > 0) { - nTokens = fCompileArguments.length; - rv = new String[nTokens + tso.size()]; - System.arraycopy(fCompileArguments, 0, rv, 0, nTokens); - } - else { - rv = new String[tso.size()]; - } - for (int i = 0; i < tso.size(); ++i) { - rv[nTokens + i] = tso.get(i); - } - return rv; - } - -} +/******************************************************************************* + * Copyright (c) 2004, 2011 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 + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM - Initial API and implementation + *******************************************************************************/ +package org.eclipse.cdt.make.internal.core.scannerconfig2; + +import java.util.List; + +import org.eclipse.cdt.core.CCProjectNature; +import org.eclipse.cdt.core.CProjectNature; +import org.eclipse.cdt.make.core.MakeCorePlugin; +import org.eclipse.cdt.make.core.scannerconfig.ScannerInfoTypes; +import org.eclipse.cdt.make.internal.core.scannerconfig.gnu.GCCScannerConfigUtil; +import org.eclipse.core.resources.IProject; +import org.eclipse.core.runtime.CoreException; + +/** + * Runs a command to retrieve compiler intrinsic scanner info from 'specs' file. + * + * @author vhirsl + */ +public class GCCSpecsRunSIProvider extends DefaultRunSIProvider { + /* (non-Javadoc) + * @see org.eclipse.cdt.make.internal.core.scannerconfig2.DefaultRunSIProvider#initialize() + */ + @Override + protected boolean initialize() { + boolean rc = super.initialize(); + + if (rc) { + String targetFile = "dummy"; //$NON-NLS-1$ + IProject project = resource.getProject(); + try { + if (project.hasNature(CCProjectNature.CC_NATURE_ID)) { + targetFile = GCCScannerConfigUtil.CPP_SPECS_FILE; + } + else if (project.hasNature(CProjectNature.C_NATURE_ID)) { + targetFile = GCCScannerConfigUtil.C_SPECS_FILE; + } + // replace string variables in compile arguments + // TODO Vmir - use string variable replacement + for (int i = 0; i < fCompileArguments.length; ++i) { + fCompileArguments[i] = fCompileArguments[i].replaceAll("\\$\\{plugin_state_location\\}", //$NON-NLS-1$ + MakeCorePlugin.getWorkingDirectory().toString()); + fCompileArguments[i] = fCompileArguments[i].replaceAll("\\$\\{specs_file\\}", targetFile); //$NON-NLS-1$ + } + } catch (CoreException e) { + //TODO VMIR better error handling + MakeCorePlugin.log(e.getStatus()); + rc = false; + } + } + return rc; + } + + /* (non-Javadoc) + * @see org.eclipse.cdt.make.internal.core.scannerconfig2.DefaultRunSIProvider#prepareArguments(boolean) + */ + @Override + protected String[] prepareArguments(boolean isDefaultCommand) { + if (collector == null) + return fCompileArguments; + + @SuppressWarnings("unchecked") + List tso = collector.getCollectedScannerInfo(resource.getProject(), ScannerInfoTypes.TARGET_SPECIFIC_OPTION); + if (tso == null || tso.size() == 0) { + return fCompileArguments; + } + + String[] rv = null; + // commandArguments may have multiple arguments; tokenizing + int nTokens = 0; + if (fCompileArguments != null && fCompileArguments.length > 0) { + nTokens = fCompileArguments.length; + rv = new String[nTokens + tso.size()]; + System.arraycopy(fCompileArguments, 0, rv, 0, nTokens); + } + else { + rv = new String[tso.size()]; + } + for (int i = 0; i < tso.size(); ++i) { + rv[nTokens + i] = tso.get(i); + } + return rv; + } + +} diff --git a/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/internal/core/Configuration.java b/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/internal/core/Configuration.java index d0355fa95ad..c9316856981 100644 --- a/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/internal/core/Configuration.java +++ b/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/internal/core/Configuration.java @@ -338,9 +338,9 @@ public class Configuration extends BuildObject implements IConfiguration, IBuild if (parentConfig != null) { name = parentConfig.getName(); - // If this contructor is called to clone an existing - // configuration, the parent of the parent should be stored. - // As of 2.1, there is still one single level of inheritence to + // If this constructor is called to clone an existing + // configuration, the parent of the parent should be stored. + // As of 2.1, there is still one single level of inheritance to // worry about parent = parentConfig.getParent() == null ? parentConfig : parentConfig.getParent(); } @@ -486,8 +486,8 @@ public class Configuration extends BuildObject implements IConfiguration, IBuild // if(!baseCfg.isExtensionConfig) // cloneChildren = true; - // If this contructor is called to clone an existing - // configuration, the parent of the cloning config should be stored. + // If this constructor is called to clone an existing + // configuration, the parent of the cloning config should be stored. parent = baseCfg.isExtensionConfig || baseCfg.getParent() == null ? baseCfg : baseCfg.getParent(); // Copy the remaining attributes @@ -634,8 +634,8 @@ public class Configuration extends BuildObject implements IConfiguration, IBuild if(!cloneConfig.isExtensionConfig) cloneChildren = true; - // If this contructor is called to clone an existing - // configuration, the parent of the cloning config should be stored. + // If this constructor is called to clone an existing + // configuration, the parent of the cloning config should be stored. parent = cloneConfig.isExtensionConfig || cloneConfig.getParent() == null ? cloneConfig : cloneConfig.getParent(); parentId = parent.getId(); diff --git a/build/org.eclipse.cdt.managedbuilder.gnu.ui/src/org/eclipse/cdt/managedbuilder/gnu/cygwin/GnuCygwinConfigurationEnvironmentSupplier.java b/build/org.eclipse.cdt.managedbuilder.gnu.ui/src/org/eclipse/cdt/managedbuilder/gnu/cygwin/GnuCygwinConfigurationEnvironmentSupplier.java index 90f9b69d47f..dafa734e209 100644 --- a/build/org.eclipse.cdt.managedbuilder.gnu.ui/src/org/eclipse/cdt/managedbuilder/gnu/cygwin/GnuCygwinConfigurationEnvironmentSupplier.java +++ b/build/org.eclipse.cdt.managedbuilder.gnu.ui/src/org/eclipse/cdt/managedbuilder/gnu/cygwin/GnuCygwinConfigurationEnvironmentSupplier.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2005, 2010 Intel Corporation and others. + * Copyright (c) 2005, 2011 Intel 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 @@ -22,27 +22,50 @@ import org.eclipse.cdt.managedbuilder.internal.envvar.BuildEnvVar; */ public class GnuCygwinConfigurationEnvironmentSupplier implements IConfigurationEnvironmentVariableSupplier { + + private static final String PATH = "PATH"; //$NON-NLS-1$ + private static final String DELIMITER_UNIX = ":"; //$NON-NLS-1$ + private static final String PROPERTY_DELIMITER = "path.separator"; //$NON-NLS-1$ + private static final String PROPERTY_OSNAME = "os.name"; //$NON-NLS-1$ + + private static final String LANG = "LANG"; //$NON-NLS-1$ + private static final String LC_ALL = "LC_ALL"; //$NON-NLS-1$ + private static final String LC_MESSAGES = "LC_MESSAGES"; //$NON-NLS-1$ - static final String VARNAME = "PATH"; //$NON-NLS-1$ - static final String DELIMITER_UNIX = ":"; //$NON-NLS-1$ - static final String PROPERTY_DELIMITER = "path.separator"; //$NON-NLS-1$ - static final String PROPERTY_OSNAME = "os.name"; //$NON-NLS-1$ /* (non-Javadoc) * @see org.eclipse.cdt.managedbuilder.envvar.IConfigurationEnvironmentVariableSupplier#getVariable(java.lang.String, org.eclipse.cdt.managedbuilder.core.IConfiguration, org.eclipse.cdt.managedbuilder.envvar.IEnvironmentVariableProvider) */ @Override public IBuildEnvironmentVariable getVariable(String variableName, IConfiguration configuration, IEnvironmentVariableProvider provider) { + + if (variableName == null) + return null; if (!System.getProperty(PROPERTY_OSNAME).toLowerCase().startsWith("windows ")) //$NON-NLS-1$ return null; + + if (variableName.equalsIgnoreCase(PATH)) { + String p = CygwinPathResolver.getBinPath(); + if (p != null) + return new BuildEnvVar(PATH, p.replace('/','\\'), IBuildEnvironmentVariable.ENVVAR_PREPEND, System.getProperty(PROPERTY_DELIMITER, DELIMITER_UNIX)); + } else if (variableName.equalsIgnoreCase(LANG)) { + // Workaround for not being able to select encoding for CDT console -> change codeset to Latin1 + String langValue = System.getenv(LANG); + if (langValue == null || langValue.length() == 0) + langValue = System.getenv(LC_ALL); + if (langValue == null || langValue.length() == 0) + langValue = System.getenv(LC_MESSAGES); + if (langValue != null && langValue.length() > 0) + // langValue is [language[_territory][.codeset][@modifier]], i.e. "en_US.UTF-8@dict" + // we replace codeset with Latin1 as CDT console garbles UTF + // and ignore modifier which is not used by LANG + langValue = langValue.replaceFirst("([^.@]*)(\\..*)?(@.*)?", "$1.ISO-8859-1"); //$NON-NLS-1$ //$NON-NLS-2$ + else + langValue = "C.ISO-8859-1"; //$NON-NLS-1$ - if (variableName == null) return null; - if (!VARNAME.equalsIgnoreCase(variableName)) return null; - - String p = CygwinPathResolver.getBinPath(); - if (p != null) - return new BuildEnvVar(VARNAME, p.replace('/','\\'), IBuildEnvironmentVariable.ENVVAR_PREPEND, System.getProperty(PROPERTY_DELIMITER, DELIMITER_UNIX)); + return new BuildEnvVar(LANG, langValue); + } return null; } @@ -53,9 +76,13 @@ public class GnuCygwinConfigurationEnvironmentSupplier implements public IBuildEnvironmentVariable[] getVariables( IConfiguration configuration, IEnvironmentVariableProvider provider) { - IBuildEnvironmentVariable[] tmp = new IBuildEnvironmentVariable[1]; - tmp[0] = getVariable(VARNAME, configuration, provider); - if (tmp[0] != null) return tmp; - return null; + IBuildEnvironmentVariable varLang = getVariable(LANG, configuration, provider); + IBuildEnvironmentVariable varPath = getVariable(PATH, configuration, provider); + + if (varPath != null) { + return new IBuildEnvironmentVariable[] {varLang, varPath}; + } else { + return new IBuildEnvironmentVariable[] {varLang}; + } } } diff --git a/codan/org.eclipse.cdt.codan.checkers/src/org/eclipse/cdt/codan/internal/checkers/ClassMembersInitializationChecker.java b/codan/org.eclipse.cdt.codan.checkers/src/org/eclipse/cdt/codan/internal/checkers/ClassMembersInitializationChecker.java index c0d16049b3c..5de06044fcc 100644 --- a/codan/org.eclipse.cdt.codan.checkers/src/org/eclipse/cdt/codan/internal/checkers/ClassMembersInitializationChecker.java +++ b/codan/org.eclipse.cdt.codan.checkers/src/org/eclipse/cdt/codan/internal/checkers/ClassMembersInitializationChecker.java @@ -98,8 +98,8 @@ public class ClassMembersInitializationChecker extends AbstractIndexAstChecker { public int visit(IASTExpression expression) { if (!constructorsStack.empty() && expression instanceof IASTFunctionCallExpression) { - Set actualContructorFields = constructorsStack.peek(); - if (!actualContructorFields.isEmpty()) { + Set actualConstructorFields = constructorsStack.peek(); + if (!actualConstructorFields.isEmpty()) { boolean skipCurrentConstructor = false; IASTFunctionCallExpression fCall = (IASTFunctionCallExpression)expression; IASTExpression fNameExp = fCall.getFunctionNameExpression(); @@ -108,7 +108,7 @@ public class ClassMembersInitializationChecker extends AbstractIndexAstChecker { IBinding fBinding = fName.getName().resolveBinding(); if (fBinding instanceof ICPPMethod) { ICPPMethod method = (ICPPMethod)fBinding; - ICompositeType constructorOwner = actualContructorFields.iterator().next().getCompositeTypeOwner(); + ICompositeType constructorOwner = actualConstructorFields.iterator().next().getCompositeTypeOwner(); if (constructorOwner == method.getClassOwner() && !method.getType().isConst()) { skipCurrentConstructor = true; } @@ -152,12 +152,12 @@ public class ClassMembersInitializationChecker extends AbstractIndexAstChecker { public int visit(IASTName name) { if (!constructorsStack.empty()) { - Set actualContructorFields = constructorsStack.peek(); - if (!actualContructorFields.isEmpty()) { + Set actualConstructorFields = constructorsStack.peek(); + if (!actualConstructorFields.isEmpty()) { IBinding binding = name.resolveBinding(); - if (actualContructorFields.contains(binding)) { + if (actualConstructorFields.contains(binding)) { if ((CPPVariableReadWriteFlags.getReadWriteFlags(name) & PDOMName.WRITE_ACCESS) != 0) { - actualContructorFields.remove(binding); + actualConstructorFields.remove(binding); } } } diff --git a/codan/org.eclipse.cdt.codan.core.test/src/org/eclipse/cdt/codan/core/internal/checkers/ClassMembersInitializationCheckerTest.java b/codan/org.eclipse.cdt.codan.core.test/src/org/eclipse/cdt/codan/core/internal/checkers/ClassMembersInitializationCheckerTest.java index a0b261b1db6..343a37d16ae 100644 --- a/codan/org.eclipse.cdt.codan.core.test/src/org/eclipse/cdt/codan/core/internal/checkers/ClassMembersInitializationCheckerTest.java +++ b/codan/org.eclipse.cdt.codan.core.test/src/org/eclipse/cdt/codan/core/internal/checkers/ClassMembersInitializationCheckerTest.java @@ -53,7 +53,7 @@ public class ClassMembersInitializationCheckerTest extends CheckerTestCase { // int m; // C() { m = 0; } // No warnings. // }; - public void testAssignmentsInContructorShouldBeChecked() { + public void testAssignmentsInConstructorShouldBeChecked() { loadCodeAndRun(getAboveComment()); checkNoErrors(); } @@ -171,7 +171,7 @@ public class ClassMembersInitializationCheckerTest extends CheckerTestCase { // int i1, i2; // }; // C::C() : i1(0) {} // 1 warning for: i2. - public void testExternalContructorHandling() { + public void testExternalConstructorHandling() { loadCodeAndRun(getAboveComment()); checkErrorLines(5); } @@ -184,7 +184,7 @@ public class ClassMembersInitializationCheckerTest extends CheckerTestCase { // T2 t2; // }; // C::C() : i1(0), t1(T1()) {} // 1 warning for: i2. - public void testExternalContructorOfTemplateClassHandling() { + public void testExternalConstructorOfTemplateClassHandling() { loadCodeAndRun(getAboveComment()); checkErrorLines(8); } @@ -196,7 +196,7 @@ public class ClassMembersInitializationCheckerTest extends CheckerTestCase { // }; // template // C::C() : i1(0) {} // 1 warning for: i2. - public void testExternalTemplateContructorHandling() { + public void testExternalTemplateConstructorHandling() { loadCodeAndRun(getAboveComment()); checkErrorLines(7); } @@ -212,7 +212,7 @@ public class ClassMembersInitializationCheckerTest extends CheckerTestCase { // template // template // C::C() : i1(0), t1(T1()) {} // 1 warning for: i2. - public void testExternalTemplateContructorOfTemplateClassHandling() { + public void testExternalTemplateConstructorOfTemplateClassHandling() { loadCodeAndRun(getAboveComment()); checkErrorLines(11); } diff --git a/codan/org.eclipse.cdt.codan.core.test/src/org/eclipse/cdt/codan/core/internal/checkers/ReturnCheckerTest.java b/codan/org.eclipse.cdt.codan.core.test/src/org/eclipse/cdt/codan/core/internal/checkers/ReturnCheckerTest.java index 9a09a8c7d8a..95519bf9fb6 100644 --- a/codan/org.eclipse.cdt.codan.core.test/src/org/eclipse/cdt/codan/core/internal/checkers/ReturnCheckerTest.java +++ b/codan/org.eclipse.cdt.codan.core.test/src/org/eclipse/cdt/codan/core/internal/checkers/ReturnCheckerTest.java @@ -122,7 +122,7 @@ public class ReturnCheckerTest extends CheckerTestCase { // return; // } // }; - public void testContructorRetValue() { + public void testConstructorRetValue() { loadCodeAndRunCpp(getAboveComment()); checkErrorLine(3, ReturnChecker.RET_ERR_VALUE_ID); } @@ -136,7 +136,7 @@ public class ReturnCheckerTest extends CheckerTestCase { // return; // } // }; - public void testContructor_Bug323602() { + public void testConstructor_Bug323602() { IProblemPreference macro = getPreference(ReturnChecker.RET_NO_VALUE_ID, ReturnChecker.PARAM_IMPLICIT); macro.setValue(Boolean.TRUE); loadCodeAndRunCpp(getAboveComment()); diff --git a/core/org.eclipse.cdt.core.aix/library/openpty.c b/core/org.eclipse.cdt.core.aix/library/openpty.c index eb75489c629..954b2b6b852 100644 --- a/core/org.eclipse.cdt.core.aix/library/openpty.c +++ b/core/org.eclipse.cdt.core.aix/library/openpty.c @@ -86,7 +86,7 @@ ptym_open(char * pts_name) char *ptr; strcpy(pts_name, "/dev/ptmx"); - fdm = getpt(); + fdm = posix_openpt(O_RDWR); if (fdm < 0) return -1; if (grantpt(fdm) < 0) { /* grant access to slave */ diff --git a/core/org.eclipse.cdt.core.aix/os/aix/ppc/libpty.so b/core/org.eclipse.cdt.core.aix/os/aix/ppc/libpty.so index 67ad7692422..d5aed7004d4 100644 Binary files a/core/org.eclipse.cdt.core.aix/os/aix/ppc/libpty.so and b/core/org.eclipse.cdt.core.aix/os/aix/ppc/libpty.so differ diff --git a/core/org.eclipse.cdt.core.aix/os/aix/ppc/libspawner.so b/core/org.eclipse.cdt.core.aix/os/aix/ppc/libspawner.so index e7b411361b0..26dccd762c1 100644 Binary files a/core/org.eclipse.cdt.core.aix/os/aix/ppc/libspawner.so and b/core/org.eclipse.cdt.core.aix/os/aix/ppc/libspawner.so differ diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2CPPSpecTest.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2CPPSpecTest.java index fae5b672666..156d1e97c51 100644 --- a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2CPPSpecTest.java +++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2CPPSpecTest.java @@ -1941,33 +1941,34 @@ public class AST2CPPSpecTest extends AST2SpecBaseTest { parse(getAboveComment(), ParserLanguage.CPP, true, 0); } - // void f(double& a) { a += 3.14; } - // // ... - // int foo() { - // double d = 0; - // f(d); - // int v[20]; - // // ... - // int& g(int i) { return v[i]; } - // // ... - // g(3) = 7; - // } - // struct link { - // link* next; - // }; - // link* first; - // void h(link*& p) // p is a reference to pointer - // { - // p->next = first; - // first = p; - // p = 0; - // } - // void k() - // { - // link* q = new link; - // h(q); - // } - public void test8_3_2s2() throws Exception { + // void f(double& a) { a += 3.14; } + // void foo1() { + // double d = 0; + // f(d); + // } + // + // int v[20]; + // int& g(int i) { return v[i]; } + // void foo2() { + // g(3) = 7; + // } + // + // struct link { + // link* next; + // }; + // link* first; + // void h(link*& p) // p is a reference to pointer + // { + // p->next = first; + // first = p; + // p = 0; + // } + // void k() + // { + // link* q = new link; + // h(q); + // } + public void test8_3_2s3() throws Exception { parse(getAboveComment(), ParserLanguage.CPP, true, 0); } diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2CPPTests.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2CPPTests.java index aef89346a57..a0e7f90ae94 100644 --- a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2CPPTests.java +++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2CPPTests.java @@ -6392,7 +6392,25 @@ public class AST2CPPTests extends AST2BaseTest { assertProblemBinding(IProblemBinding.SEMANTIC_INVALID_REDECLARATION, nc.getName(6).resolveBinding()); assertProblemBinding(IProblemBinding.SEMANTIC_INVALID_REDEFINITION, nc.getName(8).resolveBinding()); } - + + // template class A; + // template class T> class A {}; + // template class T> class A; + // template class T> class B {}; + // template class B; + // template class B {}; + public void testInvalidClassRedeclaration_364226() throws Exception { + final String code = getAboveComment(); + IASTTranslationUnit tu= parse(code, ParserLanguage.CPP, true, false); + CPPNameCollector nc= new CPPNameCollector(); + tu.accept(nc); + assertProblemBindings(nc, 4); + assertProblemBinding(IProblemBinding.SEMANTIC_INVALID_REDEFINITION, nc.getName(4).resolveBinding()); + assertProblemBinding(IProblemBinding.SEMANTIC_INVALID_REDECLARATION, nc.getName(7).resolveBinding()); + assertProblemBinding(IProblemBinding.SEMANTIC_INVALID_REDECLARATION, nc.getName(12).resolveBinding()); + assertProblemBinding(IProblemBinding.SEMANTIC_INVALID_REDEFINITION, nc.getName(14).resolveBinding()); + } + // struct Foo { // void foo(); // }; diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2TemplateTests.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2TemplateTests.java index 4b1d5d9e4d3..141ba5d68db 100644 --- a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2TemplateTests.java +++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2TemplateTests.java @@ -5583,4 +5583,59 @@ public class AST2TemplateTests extends AST2BaseTest { public void testDirectlyNestedAmbiguity_362976() throws Exception { parseAndCheckBindings(); } + + // template + // struct MaxOfN { + // template struct Max2 { + // static const X result = (x1>x2)?x1:x2; + // }; + // static const T result = Max2::result), + // p3>::result),p4>::result),p5>::result),p6>::result),p7>::result),p8>::result), + // p9>::result),p10>::result),p11>::result),p12>::result),p13>::result),p14>::result), + // p15>::result),p16>::result),p17>::result),p18>::result),p19>::result),p20>::result; + // }; + // int main(){ + // return MaxOfN::result; + // } + public void testNestedTemplateAmbiguity_363609() throws Exception { + parseAndCheckBindings(); + } + + // struct A { + // void m() {} + // }; + // template struct B {}; + // void test() { + // B b1; + // } + public void testDefaultArgForNonTypeTemplateParameter_363743() throws Exception { + parseAndCheckBindings(); + } + + // template struct A { + // bool b; + // }; + // class B { + // }; + // template T * func(); + // void test1() { + // delete func>(); // This line causes the NPE + // } + // + // template struct C { + // int* ptr; + // }; + // void test2() { + // int a = 0, b = 1; + // delete C< a::ptr; + // delete C< A::b >::ptr; + // } + public void testTemplateAmbiguityInDeleteExpression_364225() throws Exception { + parseAndCheckBindings(); + } } diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/ClassTypeHelperTests.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/ClassTypeHelperTests.java index f3454e8e5cd..e45445d956a 100644 --- a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/ClassTypeHelperTests.java +++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/ClassTypeHelperTests.java @@ -14,7 +14,9 @@ import java.io.IOException; import junit.framework.TestSuite; +import org.eclipse.cdt.core.dom.ast.IVariable; import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassType; +import org.eclipse.cdt.core.parser.util.ASTPrinter; import org.eclipse.cdt.internal.core.dom.parser.cpp.ClassTypeHelper; import org.eclipse.cdt.internal.core.parser.ParserException; @@ -39,6 +41,13 @@ public class ClassTypeHelperTests extends AST2BaseTest { return new BindingAssertionHelper(code, true); } + // int a; + // const int& b; + public void testTemp() throws Exception { + BindingAssertionHelper helper = getAssertionHelper(); + ASTPrinter.print(helper.getTranslationUnit()); + } + // struct A { // A(const A& a); // }; diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/FaultToleranceTests.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/FaultToleranceTests.java index bd7993150fe..46beb30698f 100644 --- a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/FaultToleranceTests.java +++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/FaultToleranceTests.java @@ -278,4 +278,41 @@ public class FaultToleranceTests extends AST2BaseTest { p= getDeclaration(tu, 1); s= getDeclaration(tu, 2); } + + // TINT* f(TINT* p) { + // TINT* f1(TINT* p) { + // TINT* f2(TINT* p) { + // TINT* f3(TINT* p) { + // TINT* f4(TINT* p) { + // TINT* f5(TINT* p) { + // TINT* f6(TINT* p) { + // TINT* f7(TINT* p) { + // TINT* f8(TINT* p) { + // TINT* f9(TINT* p) { + // TINT* f10(TINT* p) { + // TINT* f11(TINT* p) { + // TINT* f12(TINT* p) { + // TINT* f13(TINT* p) { + // TINT* f14(TINT* p) { + // TINT* f15(TINT* p) { + // TINT* f16(TINT* p) { + // TINT* f17(TINT* p) { + // TINT* f18(TINT* p) { + // TINT* f19(TINT* p) { + // TINT* f20(TINT* p) { + // TINT* f21(TINT* p) { + // TINT* f22(TINT* p) { + // TINT* f23(TINT* p) { + // TINT* f24(TINT* p) { + // TINT* f25(TINT* p) { + // TINT* f26(TINT* p) { + // TINT* f27(TINT* p) { + // TINT* f28(TINT* p) { + // TINT* f29(TINT* p) { + // } + public void testPerformanceIssue_364108() throws Exception { + final String comment= getAboveComment(); + parse(comment, ParserLanguage.CPP, false, false); + parse(comment, ParserLanguage.C, false, false); + } } diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/GCCCompleteParseExtensionsTest.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/GCCCompleteParseExtensionsTest.java index 446116a1b8a..be16c393abe 100644 --- a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/GCCCompleteParseExtensionsTest.java +++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/GCCCompleteParseExtensionsTest.java @@ -216,7 +216,7 @@ public class GCCCompleteParseExtensionsTest extends AST2BaseTest { parseGPP( writer.toString() ); writer = new StringWriter(); - writer.write( "int x = ({ int foo() { return 1; } int y = foo (); int z;\n" ); //$NON-NLS-1$ + writer.write( "int x = ({ int foo(); int y = foo (); int z;\n" ); //$NON-NLS-1$ writer.write( "if (y > 0) z = y;\n" ); //$NON-NLS-1$ writer.write( "else z = - y;\n" );//$NON-NLS-1$ writer.write( "z; });\n" );//$NON-NLS-1$ diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/internal/index/tests/IndexNamesTests.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/internal/index/tests/IndexNamesTests.java index 69ae8c4a08d..2b690924beb 100644 --- a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/internal/index/tests/IndexNamesTests.java +++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/internal/index/tests/IndexNamesTests.java @@ -287,6 +287,42 @@ public class IndexNamesTests extends BaseTestCase { fIndex.releaseReadLock(); } } + + // class A { + // virtual void foo(){} + // template void SetCallback(C callback){} + // void InitCallback() { + // SetCallback(&A::foo); // Can be A::foo or B::foo + // } + // }; + // class B: public A { + // virtual void foo(){} + // }; + public void testAddressOfPolymorphicMethod_Bug363731() throws Exception { + waitForIndexer(); + String content= getComment(); + IFile file= createFile(getProject().getProject(), "test.cpp", content); + waitUntilFileIsIndexed(file, 4000); + + fIndex.acquireReadLock(); + try { + IIndexFile ifile= getIndexFile(ILinkage.CPP_LINKAGE_ID, file); + IIndexName[] names= ifile.findNames(0, content.length()); + int j= 0; + for (IIndexName indexName : names) { + if (indexName.isReference() && indexName.toString().equals("foo")) { + assertEquals(true, indexName.couldBePolymorphicMethodCall()); + assertEquals("A", CPPVisitor.getQualifiedName(fIndex.findBinding(indexName))[0]); + j++; + } else { + assertEquals(false, indexName.couldBePolymorphicMethodCall()); + } + } + assertEquals(1, j); + } finally { + fIndex.releaseReadLock(); + } + } // int _i, ri, wi, rwi; // int* rp; int* wp; int* rwp; diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/IASTDeclarator.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/IASTDeclarator.java index cc055191b56..f1d6994bd64 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/IASTDeclarator.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/IASTDeclarator.java @@ -6,7 +6,7 @@ * http://www.eclipse.org/legal/epl-v10.html * * Contributors: - * Doug Schaefer (IBM) - Initial API and implementation + * Doug Schaefer (IBM) - Initial API and implementation *******************************************************************************/ package org.eclipse.cdt.core.dom.ast; @@ -17,11 +17,10 @@ package org.eclipse.cdt.core.dom.ast; * @noimplement This interface is not intended to be implemented by clients. */ public interface IASTDeclarator extends IASTNode, IASTNameOwner { - /** * Constant - empty declarator array */ - public static final IASTDeclarator[] EMPTY_DECLARATOR_ARRAY = new IASTDeclarator[0]; + public static final IASTDeclarator[] EMPTY_DECLARATOR_ARRAY = {}; /** * POINTER_OPERATOR represents the relationship between an @@ -111,10 +110,12 @@ public interface IASTDeclarator extends IASTNode, IASTNameOwner { /** * @since 5.1 */ + @Override public IASTDeclarator copy(); /** * @since 5.3 */ + @Override public IASTDeclarator copy(CopyStyle style); } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/IASTPointerOperator.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/IASTPointerOperator.java index fe5a585b3ec..343a115cb88 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/IASTPointerOperator.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/IASTPointerOperator.java @@ -6,7 +6,7 @@ * http://www.eclipse.org/legal/epl-v10.html * * Contributors: - * Doug Schaefer (IBM) - Initial API and implementation + * Doug Schaefer (IBM) - Initial API and implementation *******************************************************************************/ package org.eclipse.cdt.core.dom.ast; @@ -15,19 +15,20 @@ package org.eclipse.cdt.core.dom.ast; * @noimplement This interface is not intended to be implemented by clients. */ public interface IASTPointerOperator extends IASTNode { - /** * Constant/sentinel. */ - public static final IASTPointerOperator[] EMPTY_ARRAY = new IASTPointerOperator[0]; + public static final IASTPointerOperator[] EMPTY_ARRAY = {}; /** * @since 5.1 */ + @Override public IASTPointerOperator copy(); /** * @since 5.3 */ + @Override public IASTPointerOperator copy(CopyStyle style); } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/cpp/ICPPASTReferenceOperator.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/cpp/ICPPASTReferenceOperator.java index c0145224e29..37c8c0c0808 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/cpp/ICPPASTReferenceOperator.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/cpp/ICPPASTReferenceOperator.java @@ -6,8 +6,8 @@ * http://www.eclipse.org/legal/epl-v10.html * * Contributors: - * Doug Schaefer (IBM) - Initial API and implementation - * Markus Schorn (Wind River Systems) + * Doug Schaefer (IBM) - Initial API and implementation + * Markus Schorn (Wind River Systems) *******************************************************************************/ package org.eclipse.cdt.core.dom.ast.cpp; @@ -20,7 +20,6 @@ import org.eclipse.cdt.core.dom.ast.IASTPointerOperator; * @noimplement This interface is not intended to be implemented by clients. */ public interface ICPPASTReferenceOperator extends IASTPointerOperator { - /** * Returns whether the operator denotes a rvalue reference (e.g. int &&). * @since 5.2 @@ -30,10 +29,12 @@ public interface ICPPASTReferenceOperator extends IASTPointerOperator { /** * @since 5.1 */ + @Override public ICPPASTReferenceOperator copy(); /** * @since 5.3 */ + @Override public ICPPASTReferenceOperator copy(CopyStyle style); } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/rewrite/TypeHelper.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/rewrite/TypeHelper.java index d3c7d53c6e7..222d970da17 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/rewrite/TypeHelper.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/rewrite/TypeHelper.java @@ -52,10 +52,9 @@ public class TypeHelper { } SizeofCalculator calc = ((ASTTranslationUnit) ast).getSizeofCalculator(); SizeAndAlignment sizeofPointer = calc.sizeAndAlignmentOfPointer(); - if (sizeofPointer == null) - return true; + long maxSize = sizeofPointer != null ? sizeofPointer.size : 4; SizeAndAlignment sizeofType = calc.sizeAndAlignment(type); - if (sizeofType == null || sizeofType.size > sizeofPointer.size) + if (sizeofType == null || sizeofType.size > maxSize) return true; } return false; diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/AbstractGNUSourceCodeParser.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/AbstractGNUSourceCodeParser.java index 54e46eacea2..ed744344988 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/AbstractGNUSourceCodeParser.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/AbstractGNUSourceCodeParser.java @@ -90,6 +90,7 @@ import org.eclipse.cdt.internal.core.parser.scanner.ILocationResolver; */ public abstract class AbstractGNUSourceCodeParser implements ISourceCodeParser { public interface ITemplateIdStrategy { + boolean shallParseAsTemplateID(IASTName name); } protected static class FoundAggregateInitializer extends Exception { @@ -243,7 +244,8 @@ public abstract class AbstractGNUSourceCodeParser implements ISourceCodeParser { throw backtrack; } - public IASTCompletionNode getCompletionNode() { + @Override + public IASTCompletionNode getCompletionNode() { return completionNode; } @@ -555,7 +557,8 @@ public abstract class AbstractGNUSourceCodeParser implements ISourceCodeParser { parsePassed = false; } - public synchronized void cancel() { + @Override + public synchronized void cancel() { isCancelled = true; } @@ -642,7 +645,8 @@ public abstract class AbstractGNUSourceCodeParser implements ISourceCodeParser { throwBacktrack(n.getOffset(), n.getLength()); } - public IASTTranslationUnit parse() { + @Override + public IASTTranslationUnit parse() { long startTime = System.currentTimeMillis(); translationUnit(); log.traceLog("Parse " //$NON-NLS-1$ @@ -1173,22 +1177,27 @@ public abstract class AbstractGNUSourceCodeParser implements ISourceCodeParser { return fUnaryOperatorOffset; } + @Override public IASTExpression copy() { throw new UnsupportedOperationException(); } + @Override public IASTExpression copy(CopyStyle style) { throw new UnsupportedOperationException(); } + @Override public IType getExpressionType() { throw new UnsupportedOperationException(); } + @Override public boolean isLValue() { throw new UnsupportedOperationException(); } + @Override public ValueCategory getValueCategory() { throw new UnsupportedOperationException(); } @@ -1198,11 +1207,14 @@ public abstract class AbstractGNUSourceCodeParser implements ISourceCodeParser { if (LT(1) == IToken.tLPAREN) { final IToken mark= mark(); final int startingOffset= mark.getOffset(); + final boolean canBeCast= canBeCastExpression(); consume(); IASTTypeId typeId= null; - try { - typeId= typeId(DeclarationOptions.TYPEID); - } catch (BacktrackException e) { + if (canBeCast) { + try { + typeId= typeId(DeclarationOptions.TYPEID); + } catch (BacktrackException e) { + } } if (typeId != null && LT(1) == IToken.tRPAREN) { consume(); @@ -1562,7 +1574,8 @@ public abstract class AbstractGNUSourceCodeParser implements ISourceCodeParser { return skipProblemConditionInParenthesis(mark.getOffset()); } - public boolean encounteredError() { + @Override + public boolean encounteredError() { return !parsePassed; } @@ -1862,9 +1875,11 @@ public abstract class AbstractGNUSourceCodeParser implements ISourceCodeParser { ds = nodeFactory.newDeclarationStatement(d); setRange(ds, d); } catch (BacktrackException b) { - if (expressionStatement == null) { - IASTNode node = b.getNodeBeforeProblem(); - if (node instanceof IASTDeclaration) { + IASTNode node = b.getNodeBeforeProblem(); + final boolean isProblemDecl = node instanceof IASTDeclaration; + if (expressionStatement == null + || (!foundSemicolon && isProblemDecl && node.contains(expressionStatement))) { + if (isProblemDecl) { ds= nodeFactory.newDeclarationStatement((IASTDeclaration) node); b.initialize(b.getProblem(), setRange(ds, node)); } @@ -2399,7 +2414,7 @@ public abstract class AbstractGNUSourceCodeParser implements ISourceCodeParser { if (token.getType() == IGCCToken.t__declspec) { consume(); if (LT(1) == IToken.tLPAREN) { - skipBrackets(IToken.tLPAREN, IToken.tRPAREN); + skipBrackets(IToken.tLPAREN, IToken.tRPAREN, 0); } } } @@ -2433,24 +2448,68 @@ public abstract class AbstractGNUSourceCodeParser implements ISourceCodeParser { } } - /** - * In case a cast expression is followed by +/- or & we should avoid it: - * (a)+1 vs. (int)+1; - * @since 4.0 - */ - protected boolean avoidCastExpressionByHeuristics() throws EndOfFileException { - if (LT(1) == IToken.tIDENTIFIER) { - if (LT(2) == IToken.tRPAREN) { - switch (LT(3)) { - case IToken.tPLUS: - case IToken.tMINUS: - case IToken.tAMPER: - case IToken.tSTAR: - return true; - } - } + protected boolean canBeCompoundLiteral() throws EndOfFileException { + IToken m= mark(); + try { + // The parenthesis cannot be followed by a binary operator + skipBrackets(IToken.tLPAREN, IToken.tRPAREN, IToken.tSEMI); + return LTcatchEOF(1) == IToken.tLBRACE; + } catch (BacktrackException bt) { + return false; + } finally { + backup(m); + } + } + + protected boolean canBeCastExpression() throws EndOfFileException { + IToken m= mark(); + try { + // The parenthesis cannot be followed by a binary operator + skipBrackets(IToken.tLPAREN, IToken.tRPAREN, IToken.tSEMI); + switch (LTcatchEOF(1)) { + case IToken.tAMPERASSIGN: + case IToken.tAND: + case IToken.tARROW: + case IToken.tARROWSTAR: + case IToken.tASSIGN: + case IToken.tBITOR: + case IToken.tBITORASSIGN: + case IToken.tCOLON: + case IToken.tCOMMA: + case IToken.tDIV: + case IToken.tDIVASSIGN: + case IToken.tDOT: + case IToken.tDOTSTAR: + case IToken.tEQUAL: + case IToken.tGT: + case IToken.tGT_in_SHIFTR: + case IToken.tGTEQUAL: + case IToken.tLBRACKET: + case IToken.tLTEQUAL: + case IToken.tMINUSASSIGN: + case IToken.tMOD: + case IToken.tMODASSIGN: + case IToken.tNOTEQUAL: + case IToken.tOR: + case IToken.tPLUSASSIGN: + case IToken.tQUESTION: + case IToken.tRBRACE: + case IToken.tRBRACKET: + case IToken.tRPAREN: + case IToken.tSEMI: + case IToken.tSHIFTL: + case IToken.tSHIFTLASSIGN: + case IToken.tSHIFTR: + case IToken.tSHIFTRASSIGN: + case IToken.tSTARASSIGN: + return false; + } + return true; + } catch (BacktrackException bt) { + return false; + } finally { + backup(m); } - return false; } protected boolean canBeTypeSpecifier() throws EndOfFileException { @@ -2511,12 +2570,12 @@ public abstract class AbstractGNUSourceCodeParser implements ISourceCodeParser { } } - protected void skipBrackets(int left, int right) throws EndOfFileException, BacktrackException { + protected void skipBrackets(int left, int right, int terminator) throws EndOfFileException, BacktrackException { consume(left); int nesting= 0; while(true) { final int lt1= LT(1); - if (lt1 == IToken.tEOC) + if (lt1 == IToken.tEOC || lt1 == terminator) throwBacktrack(LA(1)); consume(); diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/DeclarationOptions.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/DeclarationOptions.java index 93a7c5213db..b48d03820b7 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/DeclarationOptions.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/DeclarationOptions.java @@ -29,16 +29,17 @@ public class DeclarationOptions { final public static int ALLOW_FOLLOWED_BY_BRACE= 0x1000; final public static int ALLOW_OPAQUE_ENUM= 0x2000; final public static int SINGLE_DTOR= 0x4000; + final public static int ALLOW_FUNCTION_DEFINITION= 0x8000; public static final DeclarationOptions - GLOBAL= new DeclarationOptions(ALLOW_EMPTY_SPECIFIER | ALLOW_OPAQUE_ENUM), - FUNCTION_STYLE_ASM= new DeclarationOptions(ALLOW_EMPTY_SPECIFIER | NO_INITIALIZER | ALLOW_ABSTRACT), + GLOBAL= new DeclarationOptions(ALLOW_EMPTY_SPECIFIER | ALLOW_OPAQUE_ENUM | ALLOW_FUNCTION_DEFINITION), + FUNCTION_STYLE_ASM= new DeclarationOptions(ALLOW_EMPTY_SPECIFIER | NO_INITIALIZER | ALLOW_ABSTRACT | ALLOW_FUNCTION_DEFINITION), C_MEMBER= new DeclarationOptions(ALLOW_BITFIELD | ALLOW_ABSTRACT), - CPP_MEMBER= new DeclarationOptions(ALLOW_EMPTY_SPECIFIER | ALLOW_BITFIELD | NO_CTOR_STYLE_INITIALIZER), + CPP_MEMBER= new DeclarationOptions(ALLOW_EMPTY_SPECIFIER | ALLOW_BITFIELD | NO_CTOR_STYLE_INITIALIZER | ALLOW_FUNCTION_DEFINITION), LOCAL= new DeclarationOptions(ALLOW_OPAQUE_ENUM), PARAMETER= new DeclarationOptions(ALLOW_ABSTRACT | ALLOW_PARAMETER_PACKS | REQUIRE_SIMPLE_NAME | NO_BRACED_INITIALIZER | NO_CTOR_STYLE_INITIALIZER), TYPEID= new DeclarationOptions(REQUIRE_ABSTRACT | NO_INITIALIZER), - TYPEID_TRAILING_RETURN_TYPE= new DeclarationOptions(REQUIRE_ABSTRACT | NO_INITIALIZER | ALLOW_FOLLOWED_BY_BRACE), + TYPEID_TRAILING_RETURN_TYPE= new DeclarationOptions(REQUIRE_ABSTRACT | NO_INITIALIZER | ALLOW_FOLLOWED_BY_BRACE | ALLOW_FUNCTION_DEFINITION), TYPEID_NEW= new DeclarationOptions(REQUIRE_ABSTRACT | NO_INITIALIZER | NO_FUNCTIONS | NO_NESTED | ALLOW_FOLLOWED_BY_BRACE), TYPEID_CONVERSION= new DeclarationOptions(REQUIRE_ABSTRACT | NO_INITIALIZER | NO_FUNCTIONS | NO_NESTED), EXCEPTION= new DeclarationOptions(ALLOW_ABSTRACT | NO_INITIALIZER), @@ -60,6 +61,7 @@ public class DeclarationOptions { final public boolean fRequireSimpleName; final public boolean fAllowOpaqueEnum; final public boolean fSingleDtor; + final public boolean fAllowFunctionDefinition; public DeclarationOptions(int options) { fAllowEmptySpecifier= (options & ALLOW_EMPTY_SPECIFIER) != 0; @@ -76,5 +78,6 @@ public class DeclarationOptions { fCanBeFollowedByBrace= fAllowBracedInitializer || (options & ALLOW_FOLLOWED_BY_BRACE) != 0; fAllowOpaqueEnum= (options & ALLOW_OPAQUE_ENUM) != 0; fSingleDtor= (options & SINGLE_DTOR) != 0; + fAllowFunctionDefinition= (options & ALLOW_FUNCTION_DEFINITION) != 0; } } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/c/GNUCSourceParser.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/c/GNUCSourceParser.java index cb269070476..fc43de3fe4d 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/c/GNUCSourceParser.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/c/GNUCSourceParser.java @@ -1754,7 +1754,7 @@ public class GNUCSourceParser extends AbstractGNUSourceCodeParser { final IToken current = LA(1); int startingOffset = current.getOffset(); if (current.getType() == IToken.tLBRACKET && supportParameterInfoBlock) { - skipBrackets(IToken.tLBRACKET, IToken.tRBRACKET); + skipBrackets(IToken.tLBRACKET, IToken.tRBRACKET, 0); } IASTDeclSpecifier declSpec = null; diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTReferenceOperator.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTReferenceOperator.java index 3820b979e29..395d54479af 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTReferenceOperator.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTReferenceOperator.java @@ -6,8 +6,8 @@ * http://www.eclipse.org/legal/epl-v10.html * * Contributors: - * John Camelon (IBM) - Initial API and implementation - * Markus Schorn (Wind River Systems) + * John Camelon (IBM) - Initial API and implementation + * Markus Schorn (Wind River Systems) *******************************************************************************/ package org.eclipse.cdt.internal.core.dom.parser.cpp; @@ -19,21 +19,23 @@ import org.eclipse.cdt.internal.core.dom.parser.ASTNode; * Reference operator for declarators. */ public class CPPASTReferenceOperator extends ASTNode implements ICPPASTReferenceOperator { - private final boolean fIsRValue; public CPPASTReferenceOperator(boolean isRValueReference) { fIsRValue= isRValueReference; } + @Override public boolean isRValueReference() { return fIsRValue; } + @Override public CPPASTReferenceOperator copy() { return copy(CopyStyle.withoutLocations); } + @Override public CPPASTReferenceOperator copy(CopyStyle style) { CPPASTReferenceOperator copy = new CPPASTReferenceOperator(fIsRValue); copy.setOffsetAndLength(this); @@ -47,8 +49,8 @@ public class CPPASTReferenceOperator extends ASTNode implements ICPPASTReference public boolean accept(ASTVisitor action) { if (action.shouldVisitPointerOperators) { switch (action.visit(this)) { - case ASTVisitor.PROCESS_ABORT : return false; - case ASTVisitor.PROCESS_SKIP : return true; + case ASTVisitor.PROCESS_ABORT: return false; + case ASTVisitor.PROCESS_SKIP: return true; } if (action.leave(this) == ASTVisitor.PROCESS_ABORT) return false; diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPTemplateNonTypeParameter.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPTemplateNonTypeParameter.java index 7240c76ce5e..29f4703398b 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPTemplateNonTypeParameter.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPTemplateNonTypeParameter.java @@ -25,6 +25,7 @@ import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTParameterDeclaration; import org.eclipse.cdt.core.dom.ast.cpp.ICPPParameterPackType; import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateArgument; import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateNonTypeParameter; +import org.eclipse.cdt.internal.core.dom.parser.ASTQueries; import org.eclipse.cdt.internal.core.dom.parser.Value; import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPVisitor; @@ -40,6 +41,7 @@ public class CPPTemplateNonTypeParameter extends CPPTemplateParameter implements super(name); } + @Override public IASTExpression getDefault() { IASTInitializerClause def= getDefaultClause(); if (def instanceof IASTExpression) { @@ -59,7 +61,7 @@ public class CPPTemplateNonTypeParameter extends CPPTemplateParameter implements IASTNode parent = name.getParent(); assert parent instanceof IASTDeclarator; if (parent instanceof IASTDeclarator) { - IASTDeclarator dtor = (IASTDeclarator) parent; + IASTDeclarator dtor = ASTQueries.findOutermostDeclarator((IASTDeclarator) parent); IASTInitializer initializer = dtor.getInitializer(); if (initializer instanceof IASTEqualsInitializer) { return ((IASTEqualsInitializer) initializer).getInitializerClause(); @@ -70,6 +72,7 @@ public class CPPTemplateNonTypeParameter extends CPPTemplateParameter implements return null; } + @Override public ICPPTemplateArgument getDefaultValue() { IASTInitializerClause dc= getDefault(); IASTExpression d= null; @@ -96,6 +99,7 @@ public class CPPTemplateNonTypeParameter extends CPPTemplateParameter implements return new CPPTemplateArgument(val, t); } + @Override public IType getType() { if (type == null) { IASTNode parent= getPrimaryDeclaration().getParent(); @@ -110,28 +114,36 @@ public class CPPTemplateNonTypeParameter extends CPPTemplateParameter implements return type; } + @Override public boolean isParameterPack() { return getType() instanceof ICPPParameterPackType; } + @Override public boolean isStatic() { return false; } + @Override public boolean isExtern() { return false; } + @Override public boolean isAuto() { return false; } + @Override public boolean isRegister() { return false; } + @Override public IValue getInitialValue() { return null; } + @Override public boolean isExternC() { return false; } + @Override public boolean isMutable() { return false; } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/GNUCPPSourceParser.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/GNUCPPSourceParser.java index 46bbf254f39..5587d4346f3 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/GNUCPPSourceParser.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/GNUCPPSourceParser.java @@ -209,11 +209,15 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser { } private IASTName qualifiedName() throws BacktrackException, EndOfFileException { + return ambiguousQualifiedName(CastExprCtx.eNotInBExpr); + } + + private IASTName ambiguousQualifiedName(CastExprCtx ctx) throws BacktrackException, EndOfFileException { TemplateIdStrategy strat= new TemplateIdStrategy(); IToken m= mark(); for(;;) { try { - return qualifiedName(strat, CastExprCtx.eNotInBExpr); + return qualifiedName(ctx, strat); } catch (BacktrackException e) { if (strat.setNextAlternative()) { backup(m); @@ -223,12 +227,14 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser { } } } - + /** * Parses a qualified name. */ - private IASTName qualifiedName(ITemplateIdStrategy s, CastExprCtx ctx) throws BacktrackException, EndOfFileException { - final TemplateIdStrategy strat= (TemplateIdStrategy) s; + private IASTName qualifiedName(CastExprCtx ctx, ITemplateIdStrategy strat) throws BacktrackException, EndOfFileException { + if (strat == null) + return ambiguousQualifiedName(ctx); + ICPPASTQualifiedName qname= null; IASTName name= null; final int offset= LA(1).getOffset(); @@ -288,11 +294,7 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser { if (haveArgs == -1) { templateID= false; } else if (haveArgs == 0) { - if (strat.ignoreTemplateID()) { - templateID= false; - } else { - strat.addTemplateName(name); - } + templateID= strat.shallParseAsTemplateID(name); } } if (templateID) { @@ -350,7 +352,7 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser { return name; } - private IASTName addTemplateArguments(IASTName templateName, TemplateIdStrategy strat) throws EndOfFileException, BacktrackException { + private IASTName addTemplateArguments(IASTName templateName, ITemplateIdStrategy strat) throws EndOfFileException, BacktrackException { // Parse for template arguments consume(IToken.tLT); List list = templateArgumentList(strat); @@ -566,7 +568,7 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser { } } - private List templateArgumentList(TemplateIdStrategy strat) throws EndOfFileException, BacktrackException { + private List templateArgumentList(ITemplateIdStrategy strat) throws EndOfFileException, BacktrackException { int startingOffset = LA(1).getOffset(); int endOffset = 0; List list= null; @@ -596,7 +598,7 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser { return list; } - private IASTNode templateArgument(TemplateIdStrategy strat) throws EndOfFileException, BacktrackException { + private IASTNode templateArgument(ITemplateIdStrategy strat) throws EndOfFileException, BacktrackException { IToken argStart = mark(); ICPPASTTypeId typeId= null; int lt1= 0; @@ -742,7 +744,7 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser { return expression(ExprKind.eConstant, BinaryExprCtx.eNotInTemplateID, null, null); } - private IASTExpression expression(final ExprKind kind, final BinaryExprCtx ctx, IASTInitializerClause expr, TemplateIdStrategy strat) throws EndOfFileException, BacktrackException { + private IASTExpression expression(final ExprKind kind, final BinaryExprCtx ctx, IASTInitializerClause expr, ITemplateIdStrategy strat) throws EndOfFileException, BacktrackException { final boolean allowComma= kind==ExprKind.eExpression; boolean allowAssignment= kind !=ExprKind.eConstant; @@ -750,12 +752,6 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser { return throwExpression(); } - final boolean handleVariants= strat == null; - if (handleVariants) { - strat= new TemplateIdStrategy(); - } - - final int startOffset= expr != null ? ((ASTNode) expr).getOffset() : LA(1).getOffset(); int lt1; int conditionCount= 0; @@ -763,7 +759,7 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser { NameOrTemplateIDVariants variants= null; if (expr == null) { - Object e = castExpressionForBinaryExpression(handleVariants, strat); + Object e = castExpressionForBinaryExpression(strat); if (e instanceof IASTExpression) { expr= (IASTExpression) e; } else { @@ -934,7 +930,7 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser { // Cast expression IToken m= mark(); try { - Object e = castExpressionForBinaryExpression(handleVariants, strat); + Object e = castExpressionForBinaryExpression(strat); if (e instanceof IASTExpression) { expr= (IASTExpression) e; } else { @@ -999,18 +995,19 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser { return buildExpression(lastOperator, expr); } - public Object castExpressionForBinaryExpression(boolean handleVariants, final TemplateIdStrategy strat) + public Object castExpressionForBinaryExpression(ITemplateIdStrategy s) throws EndOfFileException, BacktrackException { - if (!handleVariants) - return castExpression(CastExprCtx.eDirectlyInBExpr, strat); + if (s != null) { + return castExpression(CastExprCtx.eDirectlyInBExpr, s); + } + TemplateIdStrategy strat= new TemplateIdStrategy(); Variant variants= null; IASTExpression singleExpression= null; IASTName[] firstNames= null; final IToken mark= mark(); IToken lastToken= null; - strat.reset(); for(;;) { try { IASTExpression e = castExpression(CastExprCtx.eDirectlyInBExpr, strat); @@ -1454,14 +1451,16 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser { // ( type-name ) { initializer-list , } IToken m = mark(); try { - int offset = consume().getOffset(); - IASTTypeId t= typeId(DeclarationOptions.TYPEID); - consume(IToken.tRPAREN); - if (LT(1) == IToken.tLBRACE) { - IASTInitializer i = bracedInitList(false); - firstExpression= nodeFactory.newTypeIdInitializerExpression(t, i); - setRange(firstExpression, offset, calculateEndOffset(i)); - break; + if (canBeCompoundLiteral()) { + int offset = consume().getOffset(); + IASTTypeId t= typeId(DeclarationOptions.TYPEID); + consume(IToken.tRPAREN); + if (LT(1) == IToken.tLBRACE) { + IASTInitializer i = bracedInitList(false); + firstExpression= nodeFactory.newTypeIdInitializerExpression(t, i); + setRange(firstExpression, offset, calculateEndOffset(i)); + break; + } } } catch (BacktrackException bt) { } @@ -1554,7 +1553,7 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser { isTemplate = true; } - IASTName name = qualifiedName(strat, ctx); + IASTName name = qualifiedName(ctx, strat); if (name == null) throwBacktrack(((ASTNode) firstExpression).getOffset(), @@ -1577,7 +1576,7 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser { isTemplate = true; } - name = qualifiedName(strat, ctx); + name = qualifiedName(ctx, strat); if (name == null) throwBacktrack(((ASTNode) firstExpression).getOffset(), @@ -1690,7 +1689,7 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser { case IToken.t_operator: case IToken.tCOMPLETION: case IToken.tBITCOMPLEMENT: { - IASTName name = qualifiedName(strat, ctx); + IASTName name = qualifiedName(ctx, strat); IASTIdExpression idExpression = nodeFactory.newIdExpression(name); ((ASTNode) idExpression).setOffsetAndLength(((ASTNode) name).getOffset(), ((ASTNode) name).getOffset() + ((ASTNode) name).getLength() - ((ASTNode) name).getOffset()); @@ -2388,7 +2387,7 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser { case IToken.t_try: case IToken.tLBRACE: case IToken.tASSIGN: // defaulted or deleted function definition - if (declarators.length != 1) + if (declarators.length != 1 || !declOption.fAllowFunctionDefinition) throwBacktrack(LA(1)); dtor= declarators[0]; @@ -2568,7 +2567,7 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser { final int startOffset= LA(1).getOffset(); if (LT(1) == IToken.tLBRACKET && supportParameterInfoBlock) { - skipBrackets(IToken.tLBRACKET, IToken.tRBRACKET); + skipBrackets(IToken.tLBRACKET, IToken.tRBRACKET, 0); } IASTDeclSpecifier declSpec= null; diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/TemplateIdStrategy.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/TemplateIdStrategy.java index 11243a01cad..efa6ef4908b 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/TemplateIdStrategy.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/TemplateIdStrategy.java @@ -14,6 +14,8 @@ package org.eclipse.cdt.internal.core.dom.parser.cpp; import java.util.BitSet; import org.eclipse.cdt.core.dom.ast.IASTName; +import org.eclipse.cdt.core.dom.ast.IASTNode; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTemplateId; import org.eclipse.cdt.core.parser.util.ArrayUtil; import org.eclipse.cdt.internal.core.dom.parser.AbstractGNUSourceCodeParser.ITemplateIdStrategy; @@ -27,50 +29,52 @@ final class TemplateIdStrategy implements ITemplateIdStrategy { private IASTName[] fTemplateNames; public TemplateIdStrategy() { - reset(); - } - - public void reset() { fCurrentBranchPoint= -1; fTemplateNames= IASTName.EMPTY_NAME_ARRAY; - if (fSimpleIDs != null) { - fSimpleIDs.clear(); - } } - public boolean ignoreTemplateID() { + @Override + public boolean shallParseAsTemplateID(IASTName name) { fCurrentBranchPoint++; - return fSimpleIDs == null ? false : fSimpleIDs.get(fCurrentBranchPoint); - } - - public void addTemplateName(IASTName name) { - fTemplateNames= ArrayUtil.append(fTemplateNames, name); + + boolean templateID= fSimpleIDs == null || !fSimpleIDs.get(fCurrentBranchPoint); + if (templateID) { + fTemplateNames= ArrayUtil.append(fTemplateNames, name); + } + return templateID; } public boolean setNextAlternative() { - final int bp = fCurrentBranchPoint; + int bp = fCurrentBranchPoint; if (bp < 0) return false; fCurrentBranchPoint= -1; + IASTName[] names = getTemplateNames(); + int nameLen= names.length; fTemplateNames= IASTName.EMPTY_NAME_ARRAY; if (fSimpleIDs == null) { fSimpleIDs= new BitSet(); } // Set a new branch as far right as possible. - final int len = fSimpleIDs.length(); - if (len <= bp) { - fSimpleIDs.set(bp); - return true; - } - - for (int branch= Math.min(bp, len-2); branch>=0; branch--) { - if (!fSimpleIDs.get(branch)) { - fSimpleIDs.clear(branch+1, len); - fSimpleIDs.set(branch); - return true; + while (bp >= 0) { + if (!fSimpleIDs.get(bp)) { + if (nameLen == 0 || !hasMultipleArgs(names[--nameLen])) { + fSimpleIDs.clear(bp+1, Integer.MAX_VALUE); + fSimpleIDs.set(bp); + return true; + } } + bp--; + } + return false; + } + + private boolean hasMultipleArgs(IASTName templateName) { + IASTNode parent= templateName.getParent(); + if (parent instanceof ICPPASTTemplateId) { + return ((ICPPASTTemplateId) parent).getTemplateArguments().length > 1; } return false; } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPSemantics.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPSemantics.java index b52271bd506..102acf013a7 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPSemantics.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPSemantics.java @@ -781,7 +781,9 @@ public class CPPSemantics { data.foundItems = ArrayUtil.addAll(Object.class, (Object[]) data.foundItems, (Object[]) results); } } else { - data.foundItems = mergePrefixResults((CharArrayObjectMap) data.foundItems, results, scoped); + @SuppressWarnings("unchecked") + final CharArrayObjectMap oldItems = (CharArrayObjectMap) data.foundItems; + data.foundItems = mergePrefixResults(oldItems, results, scoped); } } @@ -791,15 +793,17 @@ public class CPPSemantics { * @param scoped * @return */ - static CharArrayObjectMap mergePrefixResults(CharArrayObjectMap dest, Object source, boolean scoped) { + static CharArrayObjectMap mergePrefixResults(CharArrayObjectMap dest, Object source, boolean scoped) { if (source == null) return dest; - CharArrayObjectMap resultMap = (dest != null) ? dest : new CharArrayObjectMap(2); + CharArrayObjectMap resultMap = (dest != null) ? dest : new CharArrayObjectMap(2); - CharArrayObjectMap map = null; + CharArrayObjectMap map = null; Object[] objs = null; int size; if (source instanceof CharArrayObjectMap) { - map = (CharArrayObjectMap) source; + @SuppressWarnings("unchecked") + final CharArrayObjectMap sourceMap = (CharArrayObjectMap) source; + map = sourceMap; size= map.size(); } else { if (source instanceof Object[]) @@ -3499,7 +3503,7 @@ public class CPPSemantics { LookupData data = createLookupData(name); data.contentAssist = true; data.prefixLookup = prefixLookup; - data.foundItems = new CharArrayObjectMap(2); + data.foundItems = new CharArrayObjectMap(2); // Convert namespaces to scopes. List nsScopes= new ArrayList(); @@ -3567,7 +3571,8 @@ public class CPPSemantics { } } catch (DOMException e) { } - CharArrayObjectMap map = (CharArrayObjectMap) data.foundItems; + @SuppressWarnings("unchecked") + CharArrayObjectMap map = (CharArrayObjectMap) data.foundItems; IBinding[] result = IBinding.EMPTY_BINDING_ARRAY; if (!map.isEmpty()) { char[] key = null; @@ -3686,7 +3691,7 @@ public class CPPSemantics { return true; } - private static boolean isSameTemplateParameter(ICPPTemplateParameter tp1, ICPPASTTemplateParameter tp2) { + static boolean isSameTemplateParameter(ICPPTemplateParameter tp1, ICPPASTTemplateParameter tp2) { if (tp1.isParameterPack() != tp2.isParameterPack()) return false; diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPVisitor.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPVisitor.java index 571b28ac652..d5e531c20ed 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPVisitor.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPVisitor.java @@ -460,10 +460,9 @@ public class CPPVisitor extends ASTQueries { } try { - boolean template = false; + ICPPASTTemplateDeclaration templateDecl = CPPTemplates.getTemplateDeclaration(name); ICPPScope scope = (ICPPScope) getContainingScope(name); while (scope instanceof ICPPTemplateScope) { - template = true; scope= (ICPPScope) scope.getParent(); } @@ -493,35 +492,21 @@ public class CPPVisitor extends ASTQueries { if (binding instanceof ICPPClassType) { final ICPPInternalBinding ib = (ICPPInternalBinding) binding; - if ((binding instanceof ICPPClassTemplate) == template) { + if (templateParametersMatch((ICPPClassType) binding, templateDecl)) { ib.addDeclaration(elabType); return binding; } - if (CPPSemantics.declaredBefore(binding, name, false)) { + + if (CPPSemantics.declaredBefore(ib, name, false)) { return new ProblemBinding(name, IProblemBinding.SEMANTIC_INVALID_REDECLARATION); } - - // Mark the other declarations as problem and create the binding - final IASTNode[] decls = ib.getDeclarations(); - if (decls != null) { - for (IASTNode decl : decls) { - if (decl instanceof IASTName) { - final IASTName n = (IASTName) decl; - n.setBinding(new ProblemBinding(n, IProblemBinding.SEMANTIC_INVALID_REDECLARATION)); - } - } - } - IASTNode decl= ib.getDefinition(); - if (decl instanceof IASTName) { - final IASTName n = (IASTName) decl; - n.setBinding(new ProblemBinding(n, IProblemBinding.SEMANTIC_INVALID_REDEFINITION)); - } + markRedeclaration(ib); } } // Create a binding if (elabType.getKind() != IASTElaboratedTypeSpecifier.k_enum) { - if (template) + if (templateDecl != null) binding = new CPPClassTemplate(name); else binding = new CPPClassType(name, binding); @@ -535,44 +520,91 @@ public class CPPVisitor extends ASTQueries { return binding; } + public static void markRedeclaration(final ICPPInternalBinding ib) { + // Mark the other declarations as problem and create the binding + final IASTNode[] decls = ib.getDeclarations(); + if (decls != null) { + for (IASTNode decl : decls) { + if (decl instanceof IASTName) { + final IASTName n = (IASTName) decl; + n.setBinding(new ProblemBinding(n, IProblemBinding.SEMANTIC_INVALID_REDECLARATION)); + } + } + } + IASTNode decl= ib.getDefinition(); + if (decl instanceof IASTName) { + final IASTName n = (IASTName) decl; + n.setBinding(new ProblemBinding(n, IProblemBinding.SEMANTIC_INVALID_REDEFINITION)); + } + } + + /** + * Tests whether a class binding matches the template parameters of another declaration + */ + private static boolean templateParametersMatch(ICPPClassType binding, + ICPPASTTemplateDeclaration templateDecl) { + final boolean isTemplate= binding instanceof ICPPClassTemplate; + if (templateDecl == null) + return !isTemplate; + if (!isTemplate) + return false; + + ICPPTemplateParameter[] pars1 = ((ICPPClassTemplate) binding).getTemplateParameters(); + ICPPASTTemplateParameter[] pars2 = templateDecl.getTemplateParameters(); + + int i=0; + for (ICPPASTTemplateParameter p2 : pars2) { + if (i >= pars1.length) + return true; + + if (!CPPSemantics.isSameTemplateParameter(pars1[i++], p2)) + return false; + } + return true; + } + private static IBinding createBinding(ICPPASTCompositeTypeSpecifier compType) { IASTName name = compType.getName(); if (name instanceof ICPPASTQualifiedName) { IASTName[] ns = ((ICPPASTQualifiedName) name).getNames(); name = ns[ns.length - 1]; } - - IBinding binding = null; + if (name instanceof ICPPASTTemplateId) + return CPPTemplates.createBinding((ICPPASTTemplateId) name); + ICPPScope scope = (ICPPScope) getContainingScope(name); - try { - boolean template = false; + try { while (scope instanceof ICPPTemplateScope) { - template = true; scope= (ICPPScope) scope.getParent(); } - if (name instanceof ICPPASTTemplateId) { - return CPPTemplates.createBinding((ICPPASTTemplateId) name); - } - if (name.getLookupKey().length > 0 && scope != null) // can't lookup anonymous things - binding = scope.getBinding(name, false); - if (binding instanceof ICPPInternalBinding && binding instanceof ICPPClassType && name.isActive()) { - ICPPInternalBinding internal = (ICPPInternalBinding) binding; - if (internal.getDefinition() == null && (binding instanceof ICPPClassTemplate) == template) { - ASTInternal.addDefinition(internal, compType); - } else { - binding = new ProblemBinding(name, IProblemBinding.SEMANTIC_INVALID_REDEFINITION); - } - } else { - if (template) { - binding = new CPPClassTemplate(name); - } else { - binding = new CPPClassType(name, binding); - } - } } catch (DOMException e) { - binding = e.getProblem(); + return e.getProblem(); } - return binding; + + // Can't lookup anonymous names + IBinding binding= null; + ICPPASTTemplateDeclaration templateDecl = CPPTemplates.getTemplateDeclaration(name); + if (name.getLookupKey().length > 0 && scope != null) { + binding = scope.getBinding(name, false); + + if (binding instanceof ICPPInternalBinding + && binding instanceof ICPPClassType && name.isActive()) { + ICPPInternalBinding ib = (ICPPInternalBinding) binding; + if (ib.getDefinition() == null + && templateParametersMatch((ICPPClassType) binding, templateDecl)) { + ASTInternal.addDefinition(ib, compType); + return binding; + } + if (CPPSemantics.declaredBefore(ib, name, false)) { + return new ProblemBinding(name, IProblemBinding.SEMANTIC_INVALID_REDEFINITION); + } + markRedeclaration(ib); + } + } + if (templateDecl != null) + return new CPPClassTemplate(name); + + return new CPPClassType(name, binding); } private static IBinding createBinding(IASTDeclaration declaration) { diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/cpp/PDOMCPPMethod.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/cpp/PDOMCPPMethod.java index 9262f137782..df9d4578aa9 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/cpp/PDOMCPPMethod.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/cpp/PDOMCPPMethod.java @@ -25,6 +25,7 @@ import org.eclipse.cdt.core.dom.ast.IScope; import org.eclipse.cdt.core.dom.ast.IType; import org.eclipse.cdt.core.dom.ast.IVariable; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTFieldReference; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTQualifiedName; import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassType; import org.eclipse.cdt.core.dom.ast.cpp.ICPPMethod; import org.eclipse.cdt.core.dom.ast.cpp.ICPPReferenceType; @@ -110,6 +111,7 @@ class PDOMCPPMethod extends PDOMCPPFunction implements ICPPMethod { return IIndexCPPBindingConstants.CPPMETHOD; } + @Override public boolean isVirtual() { return getBit(getAnnotation1(), PDOMCPPAnnotation.VIRTUAL_OFFSET); } @@ -120,10 +122,12 @@ class PDOMCPPMethod extends PDOMCPPFunction implements ICPPMethod { return annotation1; } + @Override public boolean isPureVirtual() { return getBit(getAnnotation1(), PDOMCPPAnnotation.PURE_VIRTUAL_OFFSET); } + @Override public boolean isDestructor() { return getBit(getAnnotation1(), PDOMCPPAnnotation.DESTRUCTOR_OFFSET); } @@ -133,10 +137,12 @@ class PDOMCPPMethod extends PDOMCPPFunction implements ICPPMethod { return false; } + @Override public boolean isImplicit() { return getBit(getAnnotation1(), PDOMCPPAnnotation.IMPLICIT_METHOD_OFFSET); } + @Override public boolean isExplicit() { return getBit(getAnnotation1(), PDOMCPPAnnotation.EXPLICIT_METHOD_OFFSET); } @@ -169,10 +175,12 @@ class PDOMCPPMethod extends PDOMCPPFunction implements ICPPMethod { return false; } + @Override public int getVisibility() { return PDOMCPPAnnotation.getVisibility(getAnnotation()); } + @Override public ICPPClassType getClassOwner() { return (ICPPClassType) getOwner(); } @@ -194,8 +202,19 @@ class PDOMCPPMethod extends PDOMCPPFunction implements ICPPMethod { public int getAdditionalNameFlags(int standardFlags, IASTName name) { if ((standardFlags & PDOMName.IS_REFERENCE) == PDOMName.IS_REFERENCE) { IASTNode parent= name.getParent(); - if (parent instanceof ICPPASTFieldReference) { - // the name is not qualified + if (parent instanceof ICPPASTQualifiedName) { + // When taking the address of a method it will be called without suppressing + // the virtual mechanism + parent= parent.getParent(); + if (parent instanceof IASTIdExpression) { + parent= parent.getParent(); + if (parent instanceof IASTUnaryExpression) { + if (((IASTUnaryExpression) parent).getOperator() == IASTUnaryExpression.op_amper) + return PDOMName.COULD_BE_POLYMORPHIC_METHOD_CALL; + } + } + } else if (parent instanceof ICPPASTFieldReference) { + // The name is not qualified ICPPASTFieldReference fr= (ICPPASTFieldReference) parent; parent= parent.getParent(); if (parent instanceof IASTFunctionCallExpression) { @@ -221,9 +240,8 @@ class PDOMCPPMethod extends PDOMCPPFunction implements ICPPMethod { return PDOMName.COULD_BE_POLYMORPHIC_METHOD_CALL; } } - } - // calling a member from within a member - else if (parent instanceof IASTIdExpression) { + } else if (parent instanceof IASTIdExpression) { + // Calling a member from within a member if (parent.getParent() instanceof IASTFunctionCallExpression) { return PDOMName.COULD_BE_POLYMORPHIC_METHOD_CALL; } diff --git a/core/org.eclipse.cdt.ui.tests/resources/refactoring/GenerateGettersAndSetters.rts b/core/org.eclipse.cdt.ui.tests/resources/refactoring/GenerateGettersAndSetters.rts index f81bfc2c568..3afa9b7a863 100644 --- a/core/org.eclipse.cdt.ui.tests/resources/refactoring/GenerateGettersAndSetters.rts +++ b/core/org.eclipse.cdt.ui.tests/resources/refactoring/GenerateGettersAndSetters.rts @@ -30,7 +30,7 @@ public: Person myFriend; - Person(int socSecNo); // contructor + Person(int socSecNo); // constructor ~Person(); // destructor @@ -53,7 +53,7 @@ public: int gooo = 1; -#endif /*C_H_*/ +#endif /* C_H_ */ //= #ifndef C_H_ #define C_H_ @@ -70,7 +70,7 @@ public: Person myFriend; - Person(int socSecNo); // contructor + Person(int socSecNo); // constructor ~Person(); // destructor @@ -97,7 +97,7 @@ public: int gooo = 1; -#endif /*C_H_*/ +#endif /* C_H_ */ //!Generate Getters and Setters One Getter Selection with Namespace //#org.eclipse.cdt.ui.tests.refactoring.gettersandsetters.GenerateGettersAndSettersTest //@.config @@ -132,7 +132,7 @@ public: Person myFriend; - Person(int socSecNo); // contructor + Person(int socSecNo); // constructor ~Person(); // destructor @@ -157,7 +157,7 @@ public: int gooo = 1; -#endif /*C_H_*/ +#endif /* C_H_ */ //= #ifndef C_H_ @@ -177,7 +177,7 @@ public: Person myFriend; - Person(int socSecNo); // contructor + Person(int socSecNo); // constructor ~Person(); // destructor @@ -206,7 +206,7 @@ public: int gooo = 1; -#endif /*C_H_*/ +#endif /* C_H_ */ //!Generate Getters and Setters One Setter Selection //#org.eclipse.cdt.ui.tests.refactoring.gettersandsetters.GenerateGettersAndSettersTest @@ -240,7 +240,7 @@ public: Person myFriend; - Person(int socSecNo); // contructor + Person(int socSecNo); // constructor ~Person(); // destructor @@ -264,7 +264,7 @@ public: int gooo = 1; -#endif /*C_H_*/ +#endif /* C_H_ */ //= #ifndef C_H_ #define C_H_ @@ -281,7 +281,7 @@ public: Person myFriend; - Person(int socSecNo); // contructor + Person(int socSecNo); // constructor ~Person(); // destructor @@ -309,7 +309,7 @@ public: int gooo = 1; -#endif /*C_H_*/ +#endif /* C_H_ */ //!Generate Getters and Setters Getter and Setter Selection //#org.eclipse.cdt.ui.tests.refactoring.gettersandsetters.GenerateGettersAndSettersTest //@.config @@ -343,7 +343,7 @@ public: Person myFriend; - Person(int socSecNo); // contructor + Person(int socSecNo); // constructor ~Person(); // destructor @@ -367,7 +367,7 @@ public: int gooo = 1; -#endif /*C_H_*/ +#endif /* C_H_ */ //= #ifndef C_H_ #define C_H_ @@ -384,7 +384,7 @@ public: Person myFriend; - Person(int socSecNo); // contructor + Person(int socSecNo); // constructor ~Person(); // destructor @@ -416,7 +416,7 @@ public: int gooo = 1; -#endif /*C_H_*/ +#endif /* C_H_ */ //!Generate Getters and Setters Multiple Selection //#org.eclipse.cdt.ui.tests.refactoring.gettersandsetters.GenerateGettersAndSettersTest //@.config @@ -450,7 +450,7 @@ public: Person myFriend; - Person(int socSecNo); // contructor + Person(int socSecNo); // constructor ~Person(); // destructor @@ -465,7 +465,7 @@ public: int gooo = 1; -#endif /*C_H_*/ +#endif /* C_H_ */ //= #ifndef C_H_ @@ -499,7 +499,7 @@ public: this->systemId = systemId; } - Person(int socSecNo); // contructor + Person(int socSecNo); // constructor ~Person(); // destructor @@ -514,7 +514,7 @@ public: int gooo = 1; -#endif /*C_H_*/ +#endif /* C_H_ */ //!Generate Getters and Setters Visibility order 1 //#org.eclipse.cdt.ui.tests.refactoring.gettersandsetters.GenerateGettersAndSettersTest @@ -596,7 +596,7 @@ private: int /*$*/id/*$$*/; }; -#endif /*C_H_*/ +#endif /* C_H_ */ //= #ifndef C_H_ @@ -616,7 +616,7 @@ public: } }; -#endif /*C_H_*/ +#endif /* C_H_ */ //!Generate Getters and Setters no Methods //#org.eclipse.cdt.ui.tests.refactoring.gettersandsetters.GenerateGettersAndSettersTest @@ -704,53 +704,37 @@ class test { #endif /* TEST_H_ */ -//!Generate Getters and Setters One Getter Selection Separate Definition +//!Generate Getters and Setters, Pass by Reference, Separate Definition //#org.eclipse.cdt.ui.tests.refactoring.gettersandsetters.GenerateGettersAndSettersTest //@.config filename=C.h getters=name +setters=name definitionSeparate=true -//@C.cpp -#include "C.h" - -int Person::SocSecNo() { - return socSecNo; -} - -int main(int argc, char** argv) { -} - -//= -#include "C.h" - -char* Person::getName() const { - return name; -} - -int Person::SocSecNo() { - return socSecNo; -} - -int main(int argc, char** argv) { -} - //@C.h #ifndef C_H_ #define C_H_ +struct FullName { + const char* first; + const char* last; + FullName(const FullName& other); + ~FullName(); +}; + class Person { private: int systemId; protected: - char* name; + FullName name; public: const int socSecNo; Person myFriend; - Person(int socSecNo); // contructor + Person(int socSecNo); // constructor ~Person(); // destructor @@ -769,25 +753,33 @@ public: int gooo = 1; -#endif /*C_H_*/ +#endif /* C_H_ */ //= #ifndef C_H_ #define C_H_ +struct FullName { + const char* first; + const char* last; + FullName(const FullName& other); + ~FullName(); +}; + class Person { private: int systemId; protected: - char* name; + FullName name; public: const int socSecNo; Person myFriend; - char* getName() const; + const FullName& getName() const; + void setName(const FullName& name); - Person(int socSecNo); // contructor + Person(int socSecNo); // constructor ~Person(); // destructor @@ -806,7 +798,35 @@ public: int gooo = 1; -#endif /*C_H_*/ +#endif /* C_H_ */ +//@C.cpp +#include "C.h" + +int Person::SocSecNo() { + return socSecNo; +} + +int main(int argc, char** argv) { +} + +//= +#include "C.h" + +const FullName& Person::getName() const { + return name; +} + +void Person::setName(const FullName& name) { + this->name = name; +} + +int Person::SocSecNo() { + return socSecNo; +} + +int main(int argc, char** argv) { +} + //!Generate Getters and Setters One Getter Selection with Namespace Separate Definition //#org.eclipse.cdt.ui.tests.refactoring.gettersandsetters.GenerateGettersAndSettersTest //@.config @@ -863,7 +883,7 @@ public: Person myFriend; - Person(int socSecNo); // contructor + Person(int socSecNo); // constructor ~Person(); // destructor @@ -888,7 +908,7 @@ public: int gooo = 1; -#endif /*C_H_*/ +#endif /* C_H_ */ //= #ifndef C_H_ @@ -908,7 +928,7 @@ public: Person myFriend; - Person(int socSecNo); // contructor + Person(int socSecNo); // constructor ~Person(); // destructor @@ -934,7 +954,7 @@ public: int gooo = 1; -#endif /*C_H_*/ +#endif /* C_H_ */ //!Generate Getters and Setters One Setter Selection Separate Definition //#org.eclipse.cdt.ui.tests.refactoring.gettersandsetters.GenerateGettersAndSettersTest @@ -984,7 +1004,7 @@ public: Person myFriend; - Person(int socSecNo); // contructor + Person(int socSecNo); // constructor ~Person(); // destructor @@ -1008,7 +1028,7 @@ public: int gooo = 1; -#endif /*C_H_*/ +#endif /* C_H_ */ //= #ifndef C_H_ #define C_H_ @@ -1025,7 +1045,7 @@ public: Person myFriend; - Person(int socSecNo); // contructor + Person(int socSecNo); // constructor ~Person(); // destructor @@ -1050,7 +1070,7 @@ public: int gooo = 1; -#endif /*C_H_*/ +#endif /* C_H_ */ //!Getter and Setter Selection Separate Definition //#org.eclipse.cdt.ui.tests.refactoring.gettersandsetters.GenerateGettersAndSettersTest //@.config @@ -1102,7 +1122,7 @@ public: Person myFriend; - Person(int socSecNo); // contructor + Person(int socSecNo); // constructor ~Person(); // destructor @@ -1126,7 +1146,7 @@ public: int gooo = 1; -#endif /*C_H_*/ +#endif /* C_H_ */ //= #ifndef C_H_ @@ -1144,7 +1164,7 @@ public: Person myFriend; - Person(int socSecNo); // contructor + Person(int socSecNo); // constructor ~Person(); // destructor @@ -1170,7 +1190,7 @@ public: int gooo = 1; -#endif /*C_H_*/ +#endif /* C_H_ */ //!Generate Getters and Setters no Methods Separate Definition //#org.eclipse.cdt.ui.tests.refactoring.gettersandsetters.GenerateGettersAndSettersTest @@ -1188,7 +1208,7 @@ private: int /*$*/id/*$$*/; }; -#endif /*C_H_*/ +#endif /* C_H_ */ //= #ifndef C_H_ @@ -1212,7 +1232,7 @@ inline void Person::setId(int id) { } -#endif /*C_H_*/ +#endif /* C_H_ */ //!No Methods Separate Definition //#org.eclipse.cdt.ui.tests.refactoring.gettersandsetters.GenerateGettersAndSettersTest diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/callhierarchy/CHQueries.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/callhierarchy/CHQueries.java index c72ba3b6a43..ecf68a72717 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/callhierarchy/CHQueries.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/callhierarchy/CHQueries.java @@ -130,7 +130,7 @@ public class CHQueries { if (CallHierarchyUI.isRelevantForCallHierarchy(binding)) { while (true) { ICElement[] defs= null; - if (binding instanceof ICPPMethod) { + if (binding instanceof ICPPMethod && name.couldBePolymorphicMethodCall()) { defs = findOverriders(index, (ICPPMethod) binding); } if (defs == null) { diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/gettersandsetters/FunctionFactory.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/gettersandsetters/GetterSetterFactory.java similarity index 69% rename from core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/gettersandsetters/FunctionFactory.java rename to core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/gettersandsetters/GetterSetterFactory.java index fa5f8886718..a428917cd12 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/gettersandsetters/FunctionFactory.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/gettersandsetters/GetterSetterFactory.java @@ -4,7 +4,7 @@ * 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 - * http://www.eclipse.org/legal/epl-v10.html + * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Institute for Software - initial API and implementation @@ -24,7 +24,9 @@ import org.eclipse.cdt.core.dom.ast.IASTNode.CopyStyle; import org.eclipse.cdt.core.dom.ast.IASTPointerOperator; import org.eclipse.cdt.core.dom.ast.IASTSimpleDeclSpecifier; import org.eclipse.cdt.core.dom.ast.IASTSimpleDeclaration; +import org.eclipse.cdt.core.dom.ast.IType; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTQualifiedName; +import org.eclipse.cdt.core.dom.rewrite.TypeHelper; import org.eclipse.cdt.core.parser.Keywords; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTBinaryExpression; @@ -37,28 +39,39 @@ import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTIdExpression; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTLiteralExpression; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTName; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTParameterDeclaration; +import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTReferenceOperator; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTReturnStatement; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTSimpleDeclSpecifier; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTSimpleDeclaration; +import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPVisitor; -public class FunctionFactory { +public class GetterSetterFactory { + private final IASTName fieldName; + private final IASTSimpleDeclaration fieldDeclaration; + private boolean passByReference; - public static IASTFunctionDefinition createGetterDefinition(IASTName fieldName, - IASTSimpleDeclaration fieldDeclaration, ICPPASTQualifiedName name) { + public GetterSetterFactory(IASTName fieldName, IASTSimpleDeclaration fieldDeclaration) { + this.fieldName = fieldName; + this.fieldDeclaration = fieldDeclaration; + IType type = CPPVisitor.createType(fieldDeclaration.getDeclSpecifier()); + passByReference = TypeHelper.shouldBePassedByReference(type, fieldDeclaration.getTranslationUnit()); + } + + public IASTFunctionDefinition createGetterDefinition(ICPPASTQualifiedName qualifiedName) { IASTFunctionDefinition getter = new CPPASTFunctionDefinition(); - getter.setDeclSpecifier(fieldDeclaration.getDeclSpecifier().copy(CopyStyle.withLocations)); - IASTDeclarator getterDeclarator = getGetterDeclarator(fieldName, fieldDeclaration, name); - // IASTFunctionDefinition. expects the outermost IASTFunctionDeclarator in declarator hierarchy + getter.setDeclSpecifier(getParamOrReturnDeclSpecifier()); + IASTDeclarator getterDeclarator = getGetterDeclarator(qualifiedName); + // IASTFunctionDefinition expects the outermost IASTFunctionDeclarator in declarator hierarchy while (!(getterDeclarator instanceof IASTFunctionDeclarator)) { getterDeclarator = getterDeclarator.getNestedDeclarator(); } getter.setDeclarator((IASTFunctionDeclarator) getterDeclarator); - getter.setBody(getGetterBody(fieldName)); + getter.setBody(getGetterBody()); return getter; } - private static CPPASTCompoundStatement getGetterBody(IASTName fieldName) { + private CPPASTCompoundStatement getGetterBody() { CPPASTCompoundStatement compound = new CPPASTCompoundStatement(); CPPASTReturnStatement returnStatement = new CPPASTReturnStatement(); CPPASTIdExpression idExpr = new CPPASTIdExpression(); @@ -70,36 +83,38 @@ public class FunctionFactory { return compound; } - private static IASTDeclarator getGetterDeclarator(IASTName fieldName, - IASTSimpleDeclaration fieldDeclaration, ICPPASTQualifiedName name) { + private IASTDeclarator getGetterDeclarator(ICPPASTQualifiedName qualifiedName) { CPPASTName getterName = new CPPASTName(); getterName.setName(GetterSetterNameGenerator.generateGetterName(fieldName).toCharArray()); - // copy declarator hierarchy + // Copy declarator hierarchy IASTDeclarator topDeclarator = fieldDeclaration.getDeclarators()[0].copy(CopyStyle.withLocations); - // find the innermost declarator in hierarchy + // Find the innermost declarator in hierarchy IASTDeclarator innermost = topDeclarator; while (innermost.getNestedDeclarator() != null) { innermost = innermost.getNestedDeclarator(); } - // create a new innermost function declarator basing on the field declarator + // Create a new innermost function declarator based on the field declarator CPPASTFunctionDeclarator functionDeclarator = new CPPASTFunctionDeclarator(); functionDeclarator.setConst(true); - if (name != null) { - name.addName(getterName); - functionDeclarator.setName(name); + if (qualifiedName != null) { + qualifiedName.addName(getterName); + functionDeclarator.setName(qualifiedName); } else { functionDeclarator.setName(getterName); } for (IASTPointerOperator pointer : innermost.getPointerOperators()){ functionDeclarator.addPointerOperator(pointer.copy(CopyStyle.withLocations)); } + if (passByReference) { + functionDeclarator.addPointerOperator(new CPPASTReferenceOperator(false)); + } - // replace innermost with functionDeclarator and return the whole declarator tree + // Replace the innermost with functionDeclarator and return the whole declarator tree if (innermost == topDeclarator) { - // no tree + // No tree return functionDeclarator; } else { IASTDeclarator parent = (IASTDeclarator) innermost.getParent(); @@ -108,16 +123,15 @@ public class FunctionFactory { } } - public static IASTFunctionDefinition createSetterDefinition(IASTName fieldName, - IASTSimpleDeclaration fieldDeclaration, ICPPASTQualifiedName name) { + public IASTFunctionDefinition createSetterDefinition(ICPPASTQualifiedName qualifiedName) { IASTFunctionDefinition setter = new CPPASTFunctionDefinition(); setter.setDeclSpecifier(getVoidDeclSpec()); - setter.setDeclarator(getSetterDeclarator(fieldName, fieldDeclaration, name)); - setter.setBody(getSetterBody(fieldDeclaration)); + setter.setDeclarator(getSetterDeclarator(qualifiedName)); + setter.setBody(getSetterBody()); return setter; } - private static CPPASTCompoundStatement getSetterBody(IASTSimpleDeclaration fieldDeclaration) { + private CPPASTCompoundStatement getSetterBody() { CPPASTCompoundStatement compound = new CPPASTCompoundStatement(); CPPASTExpressionStatement exprStmt = new CPPASTExpressionStatement(); CPPASTBinaryExpression binExpr = new CPPASTBinaryExpression(); @@ -126,7 +140,7 @@ public class FunctionFactory { innerDeclarator = innerDeclarator.getNestedDeclarator(); } IASTName fieldName = innerDeclarator.getName(); - CPPASTName parameterName = getSetterParameterName(fieldName); + CPPASTName parameterName = getSetterParameterName(); if (Arrays.equals(fieldName.getSimpleID(), parameterName.getSimpleID())) { CPPASTFieldReference fieldRef = new CPPASTFieldReference(); CPPASTLiteralExpression litExpr = new CPPASTLiteralExpression(); @@ -147,28 +161,29 @@ public class FunctionFactory { return compound; } - private static CPPASTFunctionDeclarator getSetterDeclarator(IASTName fieldName, - IASTSimpleDeclaration fieldDeclaration, ICPPASTQualifiedName name) { + private CPPASTFunctionDeclarator getSetterDeclarator(ICPPASTQualifiedName qualifiedName) { CPPASTName setterName = new CPPASTName(); setterName.setName(GetterSetterNameGenerator.generateSetterName(fieldName).toCharArray()); CPPASTFunctionDeclarator declarator = new CPPASTFunctionDeclarator(); - if (name != null) { - name.addName(setterName); - declarator.setName(name); + if (qualifiedName != null) { + qualifiedName.addName(setterName); + declarator.setName(qualifiedName); } else { declarator.setName(setterName); } CPPASTParameterDeclaration parameterDeclaration = new CPPASTParameterDeclaration(); IASTDeclarator parameterDeclarator = fieldDeclaration.getDeclarators()[0].copy(CopyStyle.withLocations); - parameterDeclarator.setName(getSetterParameterName(fieldName)); + parameterDeclarator.setName(getSetterParameterName()); + if (passByReference) { + parameterDeclarator.addPointerOperator(new CPPASTReferenceOperator(false)); + } parameterDeclaration.setDeclarator(parameterDeclarator); - parameterDeclaration.setDeclSpecifier(fieldDeclaration.getDeclSpecifier().copy( - CopyStyle.withLocations)); + parameterDeclaration.setDeclSpecifier(getParamOrReturnDeclSpecifier()); declarator.addParameterDeclaration(parameterDeclaration.copy(CopyStyle.withLocations)); return declarator; } - private static CPPASTName getSetterParameterName(IASTName fieldName) { + private CPPASTName getSetterParameterName() { String parameterName = GetterSetterNameGenerator.generateSetterParameterName(fieldName); return new CPPASTName(parameterName.toCharArray()); } @@ -179,25 +194,25 @@ public class FunctionFactory { return declSpecifier; } - public static IASTSimpleDeclaration createGetterDeclaration(IASTName fieldName, - IASTSimpleDeclaration fieldDeclaration) { + public IASTSimpleDeclaration createGetterDeclaration() { IASTSimpleDeclaration getter = new CPPASTSimpleDeclaration(); - IASTDeclSpecifier declSpec = fieldDeclaration.getDeclSpecifier(); - getter.setDeclSpecifier(declSpec.copy(CopyStyle.withLocations)); - // TODO(sprigogin): Implement return by reference -// IType type = CPPVisitor.createType(declSpec); -// if (TypeHelper.shouldBePassedByReference(type, fieldDeclaration.getTranslationUnit())) { -// declSpec.s -// } - getter.addDeclarator(getGetterDeclarator(fieldName, fieldDeclaration, null)); + getter.setDeclSpecifier(getParamOrReturnDeclSpecifier()); + getter.addDeclarator(getGetterDeclarator(null)); return getter; } - public static IASTSimpleDeclaration createSetterDeclaration(IASTName fieldName, - IASTSimpleDeclaration fieldDeclaration) { + private IASTDeclSpecifier getParamOrReturnDeclSpecifier() { + IASTDeclSpecifier declSpec = fieldDeclaration.getDeclSpecifier().copy(CopyStyle.withLocations); + if (passByReference) { + declSpec.setConst(true); + } + return declSpec; + } + + public IASTSimpleDeclaration createSetterDeclaration() { IASTSimpleDeclaration setter = new CPPASTSimpleDeclaration(); setter.setDeclSpecifier(getVoidDeclSpec()); - setter.addDeclarator(getSetterDeclarator(fieldName, fieldDeclaration, null)); + setter.addDeclarator(getSetterDeclarator(null)); return setter; } } diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/gettersandsetters/GetterSetterInsertEditProvider.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/gettersandsetters/GetterSetterInsertEditProvider.java index eb47fdb3b6a..0956d700277 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/gettersandsetters/GetterSetterInsertEditProvider.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/gettersandsetters/GetterSetterInsertEditProvider.java @@ -31,14 +31,14 @@ public class GetterSetterInsertEditProvider implements Comparable 0 && !Character.isWhitespace(firstLine.charAt(0))) - sourceLines[0]= ""; //$NON-NLS-1$ - Strings.trimIndentation(sourceLines, getTabWidth(), getTabWidth()); - - if (!Character.isWhitespace(firstLine.charAt(0))) - sourceLines[0]= firstLine; + boolean ignoreFirstLine= firstLine.length() > 0 && !Character.isWhitespace(firstLine.charAt(0)); + Strings.trimIndentation(sourceLines, getTabWidth(), getTabWidth(), !ignoreFirstLine); source = Strings.concatenate(sourceLines, delim); return source; @@ -797,6 +796,7 @@ public class CSourceHover extends AbstractCEditorTextHover { @Override public IInformationControlCreator getHoverControlCreator() { return new IInformationControlCreator() { + @Override public IInformationControl createInformationControl(Shell parent) { IEditorPart editor= getEditor(); int orientation= SWT.NONE; @@ -814,6 +814,7 @@ public class CSourceHover extends AbstractCEditorTextHover { @Override public IInformationControlCreator getInformationPresenterControlCreator() { return new IInformationControlCreator() { + @Override public IInformationControl createInformationControl(Shell parent) { IEditorPart editor= getEditor(); int orientation= SWT.NONE; diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/contentassist/InclusionProposalComputer.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/contentassist/InclusionProposalComputer.java index da4560cbb20..82d892e5c9b 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/contentassist/InclusionProposalComputer.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/contentassist/InclusionProposalComputer.java @@ -61,6 +61,7 @@ public class InclusionProposalComputer implements ICompletionProposalComputer { private String fErrorMessage; + @Override public List computeCompletionProposals(ContentAssistInvocationContext context, IProgressMonitor monitor) { List proposals= Collections.emptyList(); fErrorMessage= null; @@ -81,17 +82,21 @@ public class InclusionProposalComputer implements ICompletionProposalComputer { return proposals; } + @Override public List computeContextInformation(ContentAssistInvocationContext context, IProgressMonitor monitor) { return null; } + @Override public String getErrorMessage() { return fErrorMessage; } + @Override public void sessionEnded() { } + @Override public void sessionStarted() { } @@ -257,6 +262,9 @@ public class InclusionProposalComputer implements ICompletionProposalComputer { final int prefixLength = namePrefix.length(); final IProject project= tu.getCProject().getProject(); File[] files= fileDir.listFiles(); + if (files == null) { + return; + } IContentAssistMatcher matcher = ContentAssistMatcherFactory.getInstance().createMatcher(namePrefix); for (File file : files) { final String name= file.getName(); @@ -311,6 +319,7 @@ public class InclusionProposalComputer implements ICompletionProposalComputer { final IProject project= tu.getCProject().getProject(); parent.accept(new IResourceProxyVisitor() { boolean fFirstVisit= true; + @Override public boolean visit(IResourceProxy proxy) throws CoreException { final int type= proxy.getType(); final String name= proxy.getName(); diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/ui/actions/GenerateActionGroup.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/ui/actions/GenerateActionGroup.java index 573ff899f32..b7987e54557 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/ui/actions/GenerateActionGroup.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/ui/actions/GenerateActionGroup.java @@ -192,8 +192,8 @@ public class GenerateActionGroup extends ActionGroup implements ISelectionChange // editor.setAction("AddDelegateMethods", fAddDelegateMethods); //$NON-NLS-1$ // // fAddUnimplementedConstructors= new AddUnimplementedConstructorsAction(editor); -// fAddUnimplementedConstructors.setActionDefinitionId(ICEditorActionDefinitionIds.ADD_UNIMPLEMENTED_CONTRUCTORS); -// editor.setAction("AddUnimplementedConstructors", fAddUnimplementedConstructors); //$NON-NLS-1$ +// fAddUnimplementedConstructors.setActionDefinitionId(ICEditorActionDefinitionIds.ADD_UNIMPLEMENTED_CONSTRUCTORS); +// editor.setAction("AddUnimplementedConstructors", fAddUnimplementedConstructors); //$NON-NLS-1$ // // fGenerateConstructorUsingFields= new GenerateNewConstructorUsingFieldsAction(editor); // fGenerateConstructorUsingFields.setActionDefinitionId(ICEditorActionDefinitionIds.GENERATE_CONSTRUCTOR_USING_FIELDS); @@ -277,8 +277,8 @@ public class GenerateActionGroup extends ActionGroup implements ISelectionChange // fAddDelegateMethods.setActionDefinitionId(ICEditorActionDefinitionIds.CREATE_DELEGATE_METHODS); // // fAddUnimplementedConstructors= new AddUnimplementedConstructorsAction(site); -// fAddUnimplementedConstructors.setActionDefinitionId(ICEditorActionDefinitionIds.ADD_UNIMPLEMENTED_CONTRUCTORS); -// +// fAddUnimplementedConstructors.setActionDefinitionId(ICEditorActionDefinitionIds.ADD_UNIMPLEMENTED_CONSTRUCTORS); +// // fGenerateConstructorUsingFields= new GenerateNewConstructorUsingFieldsAction(site); // fGenerateConstructorUsingFields.setActionDefinitionId(ICEditorActionDefinitionIds.GENERATE_CONSTRUCTOR_USING_FIELDS); // diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/ui/dialogs/AbstractErrorParserBlock.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/ui/dialogs/AbstractErrorParserBlock.java index 8edd62c37e5..de9da25118b 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/ui/dialogs/AbstractErrorParserBlock.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/ui/dialogs/AbstractErrorParserBlock.java @@ -80,7 +80,7 @@ public abstract class AbstractErrorParserBlock extends AbstractCOptionPage { @Deprecated public AbstractErrorParserBlock(Preferences prefs) { this(); -// usingDeprecatedContructor = true; +// usingDeprecatedConstructor = true; fPrefs = prefs; } diff --git a/dsf/org.eclipse.cdt.dsf/.settings/.api_filters b/dsf/org.eclipse.cdt.dsf/.settings/.api_filters new file mode 100644 index 00000000000..4cde327ba3a --- /dev/null +++ b/dsf/org.eclipse.cdt.dsf/.settings/.api_filters @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/concurrent/AbstractCache.java b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/concurrent/AbstractCache.java index 1f22902065a..a4f95756dbc 100644 --- a/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/concurrent/AbstractCache.java +++ b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/concurrent/AbstractCache.java @@ -154,6 +154,27 @@ public abstract class AbstractCache implements ICache { rm.done(); } } + + private void completeWaitingRms() { + Object waiting = null; + synchronized(this) { + waiting = fWaitingList; + fWaitingList = null; + } + if (waiting != null) { + if (waiting instanceof RequestMonitor) { + completeWaitingRm((RequestMonitor)waiting); + } else if (waiting instanceof RequestMonitor[]) { + RequestMonitor[] waitingList = (RequestMonitor[])waiting; + for (int i = 0; i < waitingList.length; i++) { + if (waitingList[i] != null) { + completeWaitingRm(waitingList[i]); + } + } + } + waiting = null; + } + } private void completeWaitingRm(RequestMonitor rm) { rm.setStatus(fStatus); @@ -300,23 +321,33 @@ public abstract class AbstractCache implements ICache { fStatus = status; fValid = true; - Object waiting = null; - synchronized(this) { - waiting = fWaitingList; - fWaitingList = null; - } - if (waiting != null) { - if (waiting instanceof RequestMonitor) { - completeWaitingRm((RequestMonitor)waiting); - } else if (waiting instanceof RequestMonitor[]) { - RequestMonitor[] waitingList = (RequestMonitor[])waiting; - for (int i = 0; i < waitingList.length; i++) { - if (waitingList[i] != null) { - completeWaitingRm(waitingList[i]); - } - } - } - waiting = null; - } + completeWaitingRms(); } + + /** + * Performs the set and reset operations in one step This allows the cache to + * remain in invalid state, but to notify any waiting listeners that the state of + * the cache has changed. + * + * @param data + * The data that should be returned to any clients waiting for + * cache data and for clients requesting data until the cache is + * invalidated. + * @status The status that should be returned to any clients waiting for + * cache data and for clients requesting data until the cache is + * invalidated + * + * @see #reset(Object, IStatus) + * @since 2.3 + */ + protected void setAndReset(V data, IStatus status) { + assert fExecutor.getDsfExecutor().isInExecutorThread(); + + fData = data; + fStatus = status; + fValid = false; + + completeWaitingRms(); + } + } diff --git a/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/concurrent/RangeCache.java b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/concurrent/RangeCache.java index 9f8863c3da8..8c5c09eb979 100644 --- a/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/concurrent/RangeCache.java +++ b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/concurrent/RangeCache.java @@ -107,8 +107,7 @@ abstract public class RangeCache { protected List process() throws InvalidCacheException, CoreException { clearCanceledRequests(); - List> transactionRequests = getRequests(fOffset, fCount); - + List transactionRequests = getRequests(fOffset, fCount); validate(transactionRequests); return makeElementsListFromRequests(transactionRequests, fOffset, fCount); @@ -156,7 +155,7 @@ abstract public class RangeCache { public ICache> getRange(final long offset, final int count) { assert fExecutor.getDsfExecutor().isInExecutorThread(); - List> requests = getRequests(offset, count); + List requests = getRequests(offset, count); RequestCache> range = new RequestCache>(fExecutor) { @Override @@ -232,8 +231,8 @@ abstract public class RangeCache { } } - private List> getRequests(long fOffset, int fCount) { - List> requests = new ArrayList>(1); + private List getRequests(long fOffset, int fCount) { + List requests = new ArrayList(1); // Create a new request for the data to retrieve. Request current = new Request(fOffset, fCount); @@ -252,7 +251,7 @@ abstract public class RangeCache { // Adjust the beginning of the requested range of data. If there // is already an overlapping range in front of the requested range, // then use it. - private Request adjustRequestHead(Request request, List> transactionRequests, long offset, int count) { + private Request adjustRequestHead(Request request, List transactionRequests, long offset, int count) { SortedSet headRequests = fRequests.headSet(request); if (!headRequests.isEmpty()) { Request headRequest = headRequests.last(); @@ -276,7 +275,7 @@ abstract public class RangeCache { * @param transactionRequests * @return */ - private Request adjustRequestTail(Request current, List> transactionRequests, long offset, int count) { + private Request adjustRequestTail(Request current, List transactionRequests, long offset, int count) { // Create a duplicate of the tailSet, in order to avoid a concurrent modification exception. List tailSet = new ArrayList(fRequests.tailSet(current)); @@ -313,14 +312,13 @@ abstract public class RangeCache { return current; } - private List makeElementsListFromRequests(List> requests, long offset, int count) { + private List makeElementsListFromRequests(List requests, long offset, int count) { List retVal = new ArrayList(count); long index = offset; long end = offset + count; int requestIdx = 0; while (index < end ) { - @SuppressWarnings("unchecked") - Request request = (Request)requests.get(requestIdx); + Request request = requests.get(requestIdx); if (index < request.fOffset + request.fCount) { retVal.add( request.getData().get((int)(index - request.fOffset)) ); index ++; diff --git a/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/concurrent/RequestCache.java b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/concurrent/RequestCache.java index 76b94d6e145..636db58b525 100644 --- a/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/concurrent/RequestCache.java +++ b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/concurrent/RequestCache.java @@ -94,4 +94,13 @@ public abstract class RequestCache extends AbstractCache { } super.set(data, status); } + + @Override + protected void reset() { + if (fRm != null) { + fRm.cancel(); + fRm = null; + } + super.reset(); + } } diff --git a/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/concurrent/Transaction.java b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/concurrent/Transaction.java index ef72971b5ab..2b047bdbb96 100644 --- a/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/concurrent/Transaction.java +++ b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/concurrent/Transaction.java @@ -70,8 +70,10 @@ public abstract class Transaction { * logic once the cache object has been updated from the source. * * @return the cached data if it's valid, otherwise an exception is thrown - * @throws InvalidCacheException - * @throws CoreException + * @throws Transaction.InvalidCacheException Exception indicating that a + * cache is not valid and transaction will need to be rescheduled. + * @throws CoreException Exception indicating that one of the caches is + * in error state and transaction cannot be processed. */ abstract protected V process() throws InvalidCacheException, CoreException; @@ -149,19 +151,20 @@ public abstract class Transaction { * See {@link #validate(RequestCache)}. This variant simply validates * multiple cache objects. */ - public void validate(ICache ... caches) throws InvalidCacheException, CoreException { + public void validate(ICache ... caches) throws InvalidCacheException, CoreException { validate(Arrays.asList(caches)); } - - /** - * See {@link #validate(RequestCache)}. This variant simply validates - * multiple cache objects. - */ - public void validate(Iterable> caches) throws InvalidCacheException, CoreException { + + /** + * See {@link #validate(RequestCache)}. This variant simply validates + * multiple cache objects. + */ + public void validate(@SuppressWarnings("rawtypes") Iterable caches) throws InvalidCacheException, CoreException { // Check if any of the caches have errors: boolean allValid = true; - for (ICache cache : caches) { + for (Object cacheObj : caches) { + ICache cache = (ICache)cacheObj; if (cache.isValid()) { if (!cache.getStatus().isOK()) { throw new CoreException(cache.getStatus()); @@ -171,9 +174,9 @@ public abstract class Transaction { } } if (!allValid) { - // Throw the invalid cache exception, but first schedule a - // re-attempt of the transaction logic, to occur when the - // stale/unset cache objects have been updated + // Throw the invalid cache exception, but first schedule a + // re-attempt of the transaction logic, to occur when the + // stale/unset cache objects have been updated CountingRequestMonitor countringRm = new CountingRequestMonitor(ImmediateExecutor.getInstance(), fRm) { @Override protected void handleCompleted() { @@ -181,7 +184,8 @@ public abstract class Transaction { } }; int count = 0; - for (ICache cache : caches) { + for (Object cacheObj : caches) { + ICache cache = (ICache)cacheObj; if (!cache.isValid()) { cache.update(countringRm); count++; diff --git a/dsf/org.eclipse.cdt.examples.dsf/src_preprocess/org/eclipse/cdt/examples/dsf/dataviewer/ACPMSumDataGenerator.java b/dsf/org.eclipse.cdt.examples.dsf/src_preprocess/org/eclipse/cdt/examples/dsf/dataviewer/ACPMSumDataGenerator.java new file mode 100644 index 00000000000..889d59475dc --- /dev/null +++ b/dsf/org.eclipse.cdt.examples.dsf/src_preprocess/org/eclipse/cdt/examples/dsf/dataviewer/ACPMSumDataGenerator.java @@ -0,0 +1,234 @@ +/******************************************************************************* + * Copyright (c) 2011 Wind River Systems 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 + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +//#ifdef exercises +package org.eclipse.cdt.examples.dsf.dataviewer; +//#else +//#package org.eclipse.cdt.examples.dsf.dataviewer.answers; +//#endif + +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; +import java.util.Set; +import java.util.concurrent.RejectedExecutionException; +import java.util.concurrent.TimeUnit; + +import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor; +import org.eclipse.cdt.dsf.concurrent.DsfExecutor; +import org.eclipse.cdt.dsf.concurrent.DsfRunnable; +import org.eclipse.cdt.dsf.concurrent.ICache; +import org.eclipse.cdt.dsf.concurrent.ImmediateInDsfExecutor; +import org.eclipse.cdt.dsf.concurrent.RequestMonitor; +import org.eclipse.cdt.dsf.concurrent.Transaction; +import org.eclipse.core.runtime.CoreException; + +/** + * A data generator which performs a sum computation on data retrieved from a + * number of other data generators. The data retrieval from other generators + * is performed using ACPM caches and the result is calculated once all caches + * are valid. + *

+ * Unlike {@link AsyncSumDataGenerator}, this data generator listens to events + * from the individual the data providers. Theve events are used to + * invalidate caches to make sure that they don't return incorrect data. This + * generator also sends out events to its clients to notify them to update, or + * invalidate their caches. + *

+ */ +public class ACPMSumDataGenerator + implements IDataGenerator, IDataGenerator.Listener +{ + + /** + * DSF executor used to serialize data access within this data generator. + */ + final private DsfExecutor fExecutor; + + /** + * Data generators to retrieve original data to perform calculations on. + * The generators are accessed through the cache manager wrappers. + */ + final private DataGeneratorCacheManager[] fDataGeneratorCMs; + + /** + * List of listeners for this data generator. + */ + final private List fListeners = new LinkedList(); + + public ACPMSumDataGenerator(DsfExecutor executor, + IDataGenerator[] generators) + { + fExecutor = executor; + + // Create wrappers for data generators and add ourselves as listener + // to their events. + fDataGeneratorCMs = new DataGeneratorCacheManager[generators.length]; + ImmediateInDsfExecutor immediateExecutor = + new ImmediateInDsfExecutor(fExecutor); + for (int i = 0; i < generators.length; i++) { + fDataGeneratorCMs[i] = new DataGeneratorCacheManager( + immediateExecutor, generators[i]); + generators[i].addListener(this); + } + } + + public void getCount(final DataRequestMonitor rm) { + // Artificially delay the retrieval of the sum data to simulate + // real processing time. + fExecutor.schedule( new Runnable() { + public void run() { + // Create the transaction here to put all the ugly + // code in one place. + new Transaction() { + @Override + protected Integer process() + throws Transaction.InvalidCacheException, + CoreException + { + return processCount(this); + } + }.request(rm); + } + }, + PROCESSING_DELAY, TimeUnit.MILLISECONDS); + } + + /** + * Perform the calculation to get the max count for the given transaction. + * @param transaction The ACPM transaction to use for calculation. + * @return Calculated count. + * @throws Transaction.InvalidCacheException {@link Transaction#process} + * @throws CoreException See {@link Transaction#process} + */ + private Integer processCount(Transaction transaction) + throws Transaction.InvalidCacheException, CoreException + { + // Assemble all needed count caches into a collection. + List> countCaches = + new ArrayList>(fDataGeneratorCMs.length); + for (DataGeneratorCacheManager dataGeneratorCM : fDataGeneratorCMs) { + countCaches.add(dataGeneratorCM.getCount()); + } + // Validate all count caches at once. This executes needed requests + // in parallel. + transaction.validate(countCaches); + + // Calculate the max value and return. + int maxCount = 0; + for (ICache countCache : countCaches) { + maxCount = Math.max(maxCount, countCache.getData()); + } + return maxCount; + } + + public void getValue(final int index, final DataRequestMonitor rm) + { + // Add a processing delay. + fExecutor.schedule( new Runnable() { + public void run() { + new Transaction() { + @Override + protected Integer process() + throws Transaction.InvalidCacheException, + CoreException + { + return processValue(this, index); + } + }.request(rm); + } + }, + PROCESSING_DELAY, TimeUnit.MILLISECONDS); + } + + /** + * Perform the calculation to get the sum of values at given index. + * @param transaction The ACPM transaction to use for calculation. + * @param index Index of value to calculate. + * @return Calculated value. + * @throws Transaction.InvalidCacheException {@link Transaction#process} + * @throws CoreException See {@link Transaction#process} + */ + private Integer processValue(Transaction transaction, int index) + throws Transaction.InvalidCacheException, CoreException + { + List> valueCaches = + new ArrayList>(fDataGeneratorCMs.length); + for (DataGeneratorCacheManager dataGeneratorCM : fDataGeneratorCMs) { + valueCaches.add(dataGeneratorCM.getValue(index)); + } + // Validate all value caches at once. This executes needed requests + // in parallel. + transaction.validate(valueCaches); + + int sum = 0; + for (ICache valueCache : valueCaches) { + sum += valueCache.getData(); + } + return sum; + } + + public void shutdown(final RequestMonitor rm) { + for (DataGeneratorCacheManager dataGeneratorCM : fDataGeneratorCMs) { + dataGeneratorCM.getDataGenerator().removeListener(this); + dataGeneratorCM.dispose(); + rm.done(); + } + rm.done(); + } + + public void addListener(final Listener listener) { + // Must access fListeners on executor thread. + try { + fExecutor.execute( new DsfRunnable() { + public void run() { + fListeners.add(listener); + } + }); + } catch (RejectedExecutionException e) {} + } + + public void removeListener(final Listener listener) { + // Must access fListeners on executor thread. + try { + fExecutor.execute( new DsfRunnable() { + public void run() { + fListeners.remove(listener); + } + }); + } catch (RejectedExecutionException e) {} + } + + public void countChanged() { + // Must access fListeners on executor thread. + try { + fExecutor.execute( new DsfRunnable() { + public void run() { + for (Listener listener : fListeners) { + listener.countChanged(); + } + } + }); + } catch (RejectedExecutionException e) {} + } + + public void valuesChanged(final Set changed) { + // Must access fListeners on executor thread. + try { + fExecutor.execute( new DsfRunnable() { + public void run() { + for (Object listener : fListeners) { + ((Listener)listener).valuesChanged(changed); + } + } + }); + } catch (RejectedExecutionException e) {} + } +} diff --git a/dsf/org.eclipse.cdt.examples.dsf/src_preprocess/org/eclipse/cdt/examples/dsf/dataviewer/ACPMSumDataViewer.java b/dsf/org.eclipse.cdt.examples.dsf/src_preprocess/org/eclipse/cdt/examples/dsf/dataviewer/ACPMSumDataViewer.java new file mode 100644 index 00000000000..fd526e74f72 --- /dev/null +++ b/dsf/org.eclipse.cdt.examples.dsf/src_preprocess/org/eclipse/cdt/examples/dsf/dataviewer/ACPMSumDataViewer.java @@ -0,0 +1,482 @@ +/******************************************************************************* + * Copyright (c) 2011 Wind River Systems 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 + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +//#ifdef exercises +package org.eclipse.cdt.examples.dsf.dataviewer; +//#else +//#package org.eclipse.cdt.examples.dsf.dataviewer.answers; +//#endif + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.Set; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; + +import org.eclipse.cdt.dsf.concurrent.ConfinedToDsfExecutor; +import org.eclipse.cdt.dsf.concurrent.CountingRequestMonitor; +import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor; +import org.eclipse.cdt.dsf.concurrent.DefaultDsfExecutor; +import org.eclipse.cdt.dsf.concurrent.DsfExecutor; +import org.eclipse.cdt.dsf.concurrent.ICache; +import org.eclipse.cdt.dsf.concurrent.ImmediateExecutor; +import org.eclipse.cdt.dsf.concurrent.ImmediateInDsfExecutor; +import org.eclipse.cdt.dsf.concurrent.Query; +import org.eclipse.cdt.dsf.concurrent.ThreadSafe; +import org.eclipse.cdt.dsf.concurrent.Transaction; +import org.eclipse.cdt.dsf.ui.concurrent.DisplayDsfExecutor; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.jface.viewers.ILazyContentProvider; +import org.eclipse.jface.viewers.TableViewer; +import org.eclipse.jface.viewers.Viewer; +import org.eclipse.swt.SWT; +import org.eclipse.swt.graphics.Font; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.swt.widgets.Table; + +/** + * Data viewer based on a table, which reads data from multiple data + * providers using ACPM methods and performs a computation on the + * retrieved data. + *

+ * This example builds on the {@link AsyncSumDataViewer} example. It + * demonstrates using ACPM to solve the data consistency problem when + * retrieving data from multiple sources asynchronously. + *

+ */ +@ConfinedToDsfExecutor("fDisplayExecutor") +public class ACPMSumDataViewer implements ILazyContentProvider +{ + /** View update frequency interval. */ + final private static int UPDATE_INTERVAL = 10000; + + /** Executor to use instead of Display.asyncExec(). **/ + @ThreadSafe + final private DsfExecutor fDisplayExecutor; + + /** Executor to use when retrieving data from data providers */ + @ThreadSafe + final private ImmediateInDsfExecutor fDataExecutor; + + // The viewer and generator that this content provider using. + final private TableViewer fViewer; + final private DataGeneratorCacheManager[] fDataGeneratorCMs; + final private DataGeneratorCacheManager fSumGeneratorCM; + + // Fields used in request cancellation logic. + private List fItemDataRequestMonitors = + new LinkedList(); + private Set fIndexesToCancel = new HashSet(); + private int fCancelCallsPending = 0; + private Future fRefreshFuture; + + public ACPMSumDataViewer(TableViewer viewer, + ImmediateInDsfExecutor dataExecutor, IDataGenerator[] generators, + IDataGenerator sumGenerator) + { + fViewer = viewer; + fDisplayExecutor = DisplayDsfExecutor.getDisplayDsfExecutor( + fViewer.getTable().getDisplay()); + fDataExecutor = dataExecutor; + + // Create wrappers for data generators. Don't need to register as + // listeners to generator events because the cache managers ensure data + // are already registered for them. + fDataGeneratorCMs = new DataGeneratorCacheManager[generators.length]; + for (int i = 0; i < generators.length; i++) { + fDataGeneratorCMs[i] = + new DataGeneratorCacheManager(fDataExecutor, generators[i]); + } + fSumGeneratorCM = + new DataGeneratorCacheManager(fDataExecutor, sumGenerator); + + // Schedule a task to refresh the viewer periodically. + fRefreshFuture = fDisplayExecutor.scheduleAtFixedRate( + new Runnable() { + public void run() { + queryItemCount(); + } + }, + UPDATE_INTERVAL, UPDATE_INTERVAL, TimeUnit.MILLISECONDS); + } + + public void dispose() { + // Cancel the periodic task of refreshing the view. + fRefreshFuture.cancel(false); + + // Need to dispose cache managers that were created in this class. This + // needs to be done on the cache manager's thread. + Query disposeCacheManagersQuery = new Query() { + @Override + protected void execute(DataRequestMonitor rm) { + fSumGeneratorCM.dispose(); + for (DataGeneratorCacheManager dataGeneratorCM : + fDataGeneratorCMs) + { + dataGeneratorCM.dispose(); + } + rm.setData(new Object()); + rm.done(); + } + }; + fDataExecutor.execute(disposeCacheManagersQuery); + try { + disposeCacheManagersQuery.get(); + } + catch (InterruptedException e) {} + catch (ExecutionException e) {} + + // Cancel any outstanding data requests. + for (ValueRequestMonitor rm : fItemDataRequestMonitors) { + rm.cancel(); + } + fItemDataRequestMonitors.clear(); + } + + public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { + // Set the initial count to the viewer after the input is set. + queryItemCount(); + } + + public void updateElement(final int index) { + // Calculate the visible index range. + final int topIdx = fViewer.getTable().getTopIndex(); + final int botIdx = topIdx + getVisibleItemCount(topIdx); + + // Request the item for the given index. + queryValue(index); + + // Invoke a cancel task with a delay. The delay allows multiple cancel + // calls to be combined together improving performance of the viewer. + fCancelCallsPending++; + fDisplayExecutor.execute( + new Runnable() { public void run() { + cancelStaleRequests(topIdx, botIdx); + }}); + } + + /** + * Calculates the number of visible items based on the top item index and + * table bounds. + * @param top Index of top item. + * @return calculated number of items in viewer + */ + private int getVisibleItemCount(int top) { + Table table = fViewer.getTable(); + int itemCount = table.getItemCount(); + return Math.min( + (table.getBounds().height / table.getItemHeight()) + 2, + itemCount - top); + } + + /** + * Retrieve the current count. When a new count is set to viewer, the viewer + * will refresh all items as well. + */ + private void queryItemCount() { + // Create the request monitor to collect the count. This request + // monitor will be completed by the following transaction. + final DataRequestMonitor rm = + new DataRequestMonitor(fDisplayExecutor, null) + { + @Override + protected void handleSuccess() { + setCountToViewer(getData()); + } + @Override + protected void handleRejectedExecutionException() {} // Shutting down, ignore. + }; + + // Use a transaction, even with a single cache. This will ensure that + // if the cache is reset during processing by an event. The request + // for data will be re-issued. + fDataExecutor.execute(new Runnable() { + public void run() { + new Transaction() { + @Override + protected Integer process() + throws Transaction.InvalidCacheException, CoreException + { + return processCount(this); + } + }.request(rm); + } + }); + } + + /** + * Perform the count retrieval from the sum data generator. + * @param transaction The ACPM transaction to use for calculation. + * @return Calculated count. + * @throws Transaction.InvalidCacheException {@link Transaction#process} + * @throws CoreException See {@link Transaction#process} + */ + private Integer processCount(Transaction transaction) + throws Transaction.InvalidCacheException, CoreException + { + ICache countCache = fSumGeneratorCM.getCount(); + transaction.validate(countCache); + return countCache.getData(); + } + + /** + * Set the givne count to the viewer. This will cause the viewer will + * refresh all items' data as well. + *

Note: This method must be called in the display thread.

+ * @param count New count to set to viewer. + */ + private void setCountToViewer(int count) { + if (!fViewer.getTable().isDisposed()) { + fViewer.setItemCount(count); + fViewer.getTable().clearAll(); + } + } + + /** + * Retrieve the current value for given index. + */ + private void queryValue(final int index) { + // Create the request monitor to collect the value. This request + // monitor will be completed by the following transaction. + final ValueRequestMonitor rm = new ValueRequestMonitor(index) { + @Override + protected void handleCompleted() { + fItemDataRequestMonitors.remove(this); + if (isSuccess()) { + setValueToViewer(index, getData()); + } + } + @Override + protected void handleRejectedExecutionException() { + // Shutting down, ignore. + } + }; + + // Save the value request monitor, to cancel it if the view is + // scrolled. + fItemDataRequestMonitors.add(rm); + + // Use a transaction, even with a single cache. This will ensure that + // if the cache is reset during processing by an event. The request + // for data will be re-issued. + fDataExecutor.execute(new Runnable() { + public void run() { + new Transaction() { + @Override + protected String process() + throws Transaction.InvalidCacheException, CoreException + { + return processValue(this, index); + } + }.request(rm); + } + }); + } + + /** + * Write the view value to the viewer. + *

Note: This method must be called in the display thread.

+ * @param index Index of value to set. + * @param value New value. + */ + private void setValueToViewer(int index, String value) { + if (!fViewer.getTable().isDisposed()) { + fViewer.replace(value, index); + } + } + + /** + * Perform the calculation compose the string with data provider values + * and the sum. This implementation also validates the result. + * @param transaction The ACPM transaction to use for calculation. + * @param index Index of value to calculate. + * @return Calculated value. + * @throws Transaction.InvalidCacheException {@link Transaction#process} + * @throws CoreException See {@link Transaction#process} + */ + private String processValue(Transaction transaction, int index) + throws Transaction.InvalidCacheException, CoreException + { + List> valueCaches = + new ArrayList>(fDataGeneratorCMs.length); + for (DataGeneratorCacheManager dataGeneratorCM : fDataGeneratorCMs) { + valueCaches.add(dataGeneratorCM.getValue(index)); + } + // Validate all value caches at once. This executes needed requests + // in parallel. + transaction.validate(valueCaches); + + // TODO: evaluate sum generator cache in parallel with value caches. + ICache sumCache = fSumGeneratorCM.getValue(index); + transaction.validate(sumCache); + + // Compose the string with values, sum, and validation result. + StringBuilder result = new StringBuilder(); + int calcSum = 0; + for (ICache valueCache : valueCaches) { + if (result.length() != 0) result.append(" + "); + result.append(valueCache.getData()); + calcSum += valueCache.getData(); + } + result.append(" = "); + result.append(sumCache.getData()); + if (calcSum != sumCache.getData()) { + result.append(" !INCORRECT! "); + } + + return result.toString(); + } + + /** + * Dedicated class for data item requests. This class holds the index + * argument so it can be examined when canceling stale requests. + */ + private class ValueRequestMonitor extends DataRequestMonitor { + /** Index is used when canceling stale requests. */ + int fIndex; + + ValueRequestMonitor(int index) { + super(fDisplayExecutor, null); + fIndex = index; + } + + @Override + protected void handleRejectedExecutionException() { + // Shutting down, ignore. + } + } + + /** + * Cancels any outstanding value requests for items which are no longer + * visible in the viewer. + * + * @param topIdx Index of top visible item in viewer. + * @param botIdx Index of bottom visible item in viewer. + */ + private void cancelStaleRequests(int topIdx, int botIdx) { + // Decrement the count of outstanding cancel calls. + fCancelCallsPending--; + + // Must check again, in case disposed while re-dispatching. + if (fDataGeneratorCMs == null || fViewer.getTable().isDisposed()) { + return; + } + + // Go through the outstanding requests and cancel any that + // are not visible anymore. + for (Iterator itr = + fItemDataRequestMonitors.iterator(); itr.hasNext();) + { + ValueRequestMonitor item = itr.next(); + if (item.fIndex < topIdx || item.fIndex > botIdx) { + // Set the item to canceled status, so that the data provider + // will ignore it. + item.cancel(); + + // Add the item index to list of indexes that were canceled, + // which will be sent to the table widget. + fIndexesToCancel.add(item.fIndex); + + // Remove the item from the outstanding cancel requests. + itr.remove(); + } + } + if (!fIndexesToCancel.isEmpty() && fCancelCallsPending == 0) { + Set canceledIdxs = fIndexesToCancel; + fIndexesToCancel = new HashSet(); + + // Clear the indexes of the canceled request, so that the + // viewer knows to request them again when needed. + // Note: clearing using TableViewer.clear(int) seems very + // inefficient, it's better to use Table.clear(int[]). + int[] canceledIdxsArray = new int[canceledIdxs.size()]; + int i = 0; + for (Integer index : canceledIdxs) { + canceledIdxsArray[i++] = index; + } + fViewer.getTable().clear(canceledIdxsArray); + } + } + + /** + * The entry point for the example. + * @param args Program arguments. + */ + public static void main(String[] args) { + // Create the shell to hold the viewer. + Display display = new Display(); + Shell shell = new Shell(display, SWT.SHELL_TRIM); + shell.setLayout(new GridLayout()); + GridData data = new GridData(GridData.FILL_BOTH); + shell.setLayoutData(data); + Font font = new Font(display, "Courier", 10, SWT.NORMAL); + + // Create the table viewer. + TableViewer tableViewer = + new TableViewer(shell, SWT.BORDER | SWT.VIRTUAL); + tableViewer.getControl().setLayoutData(data); + + DsfExecutor executor = new DefaultDsfExecutor("Example executor"); + + // Create the data generator. + final IDataGenerator[] generators = new IDataGenerator[5]; + for (int i = 0; i < generators.length; i++) { + generators[i] = new DataGeneratorWithExecutor(executor); + } + final IDataGenerator sumGenerator = + new ACPMSumDataGenerator(executor, generators); + + // Create the content provider which will populate the viewer. + ACPMSumDataViewer contentProvider = new ACPMSumDataViewer( + tableViewer, new ImmediateInDsfExecutor(executor), + generators, sumGenerator); + tableViewer.setContentProvider(contentProvider); + tableViewer.setInput(new Object()); + + // Open the shell and service the display dispatch loop until user + // closes the shell. + shell.open(); + while (!shell.isDisposed()) { + if (!display.readAndDispatch()) + display.sleep(); + } + + // The IDataGenerator.shutdown() method is asynchronous, this requires + // using a query again in order to wait for its completion. + Query shutdownQuery = new Query() { + @Override + protected void execute(DataRequestMonitor rm) { + CountingRequestMonitor crm = new CountingRequestMonitor( + ImmediateExecutor.getInstance(), rm); + for (int i = 0; i < generators.length; i++) { + generators[i].shutdown(crm); + } + sumGenerator.shutdown(crm); + crm.setDoneCount(generators.length); + } + }; + + executor.execute(shutdownQuery); + try { + shutdownQuery.get(); + } catch (Exception e) {} + + // Shut down the display. + font.dispose(); + display.dispose(); + } +} diff --git a/dsf/org.eclipse.cdt.examples.dsf/src_preprocess/org/eclipse/cdt/examples/dsf/dataviewer/AsyncDataViewer.java b/dsf/org.eclipse.cdt.examples.dsf/src_preprocess/org/eclipse/cdt/examples/dsf/dataviewer/AsyncDataViewer.java index 01e29901fb2..d19ef9920ae 100644 --- a/dsf/org.eclipse.cdt.examples.dsf/src_preprocess/org/eclipse/cdt/examples/dsf/dataviewer/AsyncDataViewer.java +++ b/dsf/org.eclipse.cdt.examples.dsf/src_preprocess/org/eclipse/cdt/examples/dsf/dataviewer/AsyncDataViewer.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2006, 2009 Wind River Systems and others. + * Copyright (c) 2006, 2011 Wind River Systems 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 @@ -66,13 +66,15 @@ public class AsyncDataViewer final private IDataGenerator fDataGenerator; // Fields used in request cancellation logic. - private List fItemDataRequestMonitors = new LinkedList(); + private List fItemDataRequestMonitors = + new LinkedList(); private Set fIndexesToCancel = new HashSet(); private int fCancelCallsPending = 0; public AsyncDataViewer(TableViewer viewer, IDataGenerator generator) { fViewer = viewer; - fDisplayExecutor = DisplayDsfExecutor.getDisplayDsfExecutor(fViewer.getTable().getDisplay()); + fDisplayExecutor = DisplayDsfExecutor.getDisplayDsfExecutor( + fViewer.getTable().getDisplay()); fDataGenerator = generator; fDataGenerator.addListener(this); } @@ -104,10 +106,18 @@ public class AsyncDataViewer 1, TimeUnit.MILLISECONDS); } + /** + * Calculates the number of visible items based on the top item index and + * table bounds. + * @param top Index of top item. + * @return calculated number of items in viewer + */ private int getVisibleItemCount(int top) { Table table = fViewer.getTable(); int itemCount = table.getItemCount(); - return Math.min((table.getBounds().height / table.getItemHeight()) + 2, itemCount - top); + return Math.min( + (table.getBounds().height / table.getItemHeight()) + 2, + itemCount - top); } @ThreadSafe @@ -131,7 +141,10 @@ public class AsyncDataViewer }}); } - + /** + * Retrieve the up to date count. When a new count is set to viewer, the + * viewer will refresh all items as well. + */ private void queryItemCount() { // Request count from data provider. When the count is returned, we // have to re-dispatch into the display thread to avoid calling @@ -150,13 +163,25 @@ public class AsyncDataViewer } } }); - } - - // Dedicated class for data item requests. This class holds the index - // argument so it can be examined when canceling stale requests. - private class ValueDataRequestMonitor extends DataRequestMonitor { + + /** + * Retrieves value of an element at given index. When complete the value + * is written to the viewer. + * @param index Index of value to retrieve. + */ + private void queryValue(final int index) { + ValueDataRequestMonitor rm = new ValueDataRequestMonitor(index); + fItemDataRequestMonitors.add(rm); + fDataGenerator.getValue(index, rm); + } + + /** + * Dedicated class for data item requests. This class holds the index + * argument so it can be examined when canceling stale requests. + */ + private class ValueDataRequestMonitor extends DataRequestMonitor { /** Index is used when canceling stale requests. */ int fIndex; @@ -170,7 +195,8 @@ public class AsyncDataViewer protected void handleCompleted() { fItemDataRequestMonitors.remove(this); - // Check if the request completed successfully, otherwise ignore it. + // Check if the request completed successfully, otherwise ignore + // it. if (isSuccess()) { if (!fViewer.getTable().isDisposed()) { fViewer.replace(getData(), fIndex); @@ -178,12 +204,6 @@ public class AsyncDataViewer } } } - - private void queryValue(final int index) { - ValueDataRequestMonitor rm = new ValueDataRequestMonitor(index); - fItemDataRequestMonitors.add(rm); - fDataGenerator.getValue(index, rm); - } private void cancelStaleRequests(int topIdx, int botIdx) { // Decrement the count of outstanding cancel calls. @@ -194,7 +214,10 @@ public class AsyncDataViewer // Go through the outstanding requests and cancel any that // are not visible anymore. - for (Iterator itr = fItemDataRequestMonitors.iterator(); itr.hasNext();) { + for (Iterator itr = + fItemDataRequestMonitors.iterator(); + itr.hasNext();) + { ValueDataRequestMonitor item = itr.next(); if (item.fIndex < topIdx || item.fIndex > botIdx) { // Set the item to canceled status, so that the data provider @@ -237,14 +260,16 @@ public class AsyncDataViewer Font font = new Font(display, "Courier", 10, SWT.NORMAL); // Create the table viewer. - TableViewer tableViewer = new TableViewer(shell, SWT.BORDER | SWT.VIRTUAL); + TableViewer tableViewer = + new TableViewer(shell, SWT.BORDER | SWT.VIRTUAL); tableViewer.getControl().setLayoutData(data); // Create the data generator. final IDataGenerator generator = new DataGeneratorWithExecutor(); // Create the content provider which will populate the viewer. - AsyncDataViewer contentProvider = new AsyncDataViewer(tableViewer, generator); + AsyncDataViewer contentProvider = + new AsyncDataViewer(tableViewer, generator); tableViewer.setContentProvider(contentProvider); tableViewer.setInput(new Object()); diff --git a/dsf/org.eclipse.cdt.examples.dsf/src_preprocess/org/eclipse/cdt/examples/dsf/dataviewer/AsyncSumDataGenerator.java b/dsf/org.eclipse.cdt.examples.dsf/src_preprocess/org/eclipse/cdt/examples/dsf/dataviewer/AsyncSumDataGenerator.java new file mode 100644 index 00000000000..1d8a84c49e3 --- /dev/null +++ b/dsf/org.eclipse.cdt.examples.dsf/src_preprocess/org/eclipse/cdt/examples/dsf/dataviewer/AsyncSumDataGenerator.java @@ -0,0 +1,171 @@ +/******************************************************************************* + * Copyright (c) 2011 Wind River Systems 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 + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +//#ifdef exercises +package org.eclipse.cdt.examples.dsf.dataviewer; +//#else +//#package org.eclipse.cdt.examples.dsf.dataviewer.answers; +//#endif + +import java.util.Arrays; +import java.util.concurrent.TimeUnit; + +import org.eclipse.cdt.dsf.concurrent.CountingRequestMonitor; +import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor; +import org.eclipse.cdt.dsf.concurrent.DsfExecutor; +import org.eclipse.cdt.dsf.concurrent.ImmediateExecutor; +import org.eclipse.cdt.dsf.concurrent.RequestMonitor; + +/** + * A data generator which performs a sum computation on data retrieved from a + * number of other data generators. The data retrieval from other generators + * is performed in parallel and the result is calculated once all data is + * received. + *

+ * This calculating generator does not listen to events from the data + * providers so it relies on the client to re-retrieve data as needed. + *

+ */ +public class AsyncSumDataGenerator implements IDataGenerator { + + /** + * DSF executor used to serialize data access within this data generator. + */ + final private DsfExecutor fExecutor; + + /** + * Data generators to retrieve original data to perform calculations on. + */ + final private IDataGenerator[] fDataGenerators; + + public AsyncSumDataGenerator(DsfExecutor executor, + IDataGenerator[] generators) + { + fExecutor = executor; + fDataGenerators = generators; + } + + public void getCount(final DataRequestMonitor rm) { + // Artificially delay the retrieval of the sum data to simulate + // real processing time. + fExecutor.schedule( new Runnable() { + public void run() { + doGetCount(rm); + } + }, + PROCESSING_DELAY, TimeUnit.MILLISECONDS); + } + + /** + * Performs the actual count retrieval and calculation. + * @param rm Request monitor to complete with data. + */ + private void doGetCount(final DataRequestMonitor rm) { + // Array to store counts retrieved asynchronously + final int[] counts = new int[fDataGenerators.length]; + + // Counting request monitor is called once all data is retrieved. + final CountingRequestMonitor crm = + new CountingRequestMonitor(fExecutor, rm) + { + @Override + protected void handleSuccess() { + // Pick the highest count value. + Arrays.sort(counts, 0, counts.length - 1); + int maxCount = counts[counts.length - 1]; + rm.setData(maxCount); + rm.done(); + }; + }; + + // Each call to data generator fills in one value in array. + for (int i = 0; i < fDataGenerators.length; i++) { + final int finalI = i; + fDataGenerators[i].getCount( + new DataRequestMonitor( + ImmediateExecutor.getInstance(), crm) + { + @Override + protected void handleSuccess() { + counts[finalI] = getData(); + crm.done(); + } + }); + } + crm.setDoneCount(fDataGenerators.length); + } + + public void getValue(final int index, final DataRequestMonitor rm) + { + // Artificially delay the retrieval of the sum data to simulate + // real processing time. + fExecutor.schedule( new Runnable() { + public void run() { + doGetValue(index, rm); + } + }, + PROCESSING_DELAY, TimeUnit.MILLISECONDS); + } + + /** + * Performs the actual value retrieval and calculation. + * @param rm Request monitor to complete with data. + */ + private void doGetValue(int index, final DataRequestMonitor rm) { + // Array to store counts retrieved asynchronously + final int[] values = new int[fDataGenerators.length]; + + // Counting request monitor is called once all data is retrieved. + final CountingRequestMonitor crm = + new CountingRequestMonitor(fExecutor, rm) + { + @Override + protected void handleSuccess() { + // Sum up values in array. + int sum = 0; + for (int value : values) { + sum += value; + } + rm.setData(sum); + rm.done(); + }; + }; + + // Each call to data generator fills in one value in array. + for (int i = 0; i < fDataGenerators.length; i++) { + final int finalI = i; + fDataGenerators[i].getValue( + index, + new DataRequestMonitor( + ImmediateExecutor.getInstance(), crm) + { + @Override + protected void handleSuccess() { + values[finalI] = getData(); + crm.done(); + } + }); + } + crm.setDoneCount(fDataGenerators.length); + } + + public void shutdown(RequestMonitor rm) { + rm.done(); + } + + public void addListener(final Listener listener) { + // no events generated + } + + public void removeListener(Listener listener) { + // no events generated + } + +} diff --git a/dsf/org.eclipse.cdt.examples.dsf/src_preprocess/org/eclipse/cdt/examples/dsf/dataviewer/AsyncSumDataViewer.java b/dsf/org.eclipse.cdt.examples.dsf/src_preprocess/org/eclipse/cdt/examples/dsf/dataviewer/AsyncSumDataViewer.java new file mode 100644 index 00000000000..c34252562ee --- /dev/null +++ b/dsf/org.eclipse.cdt.examples.dsf/src_preprocess/org/eclipse/cdt/examples/dsf/dataviewer/AsyncSumDataViewer.java @@ -0,0 +1,410 @@ +/******************************************************************************* + * Copyright (c) 2011 Wind River Systems 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 + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +//#ifdef exercises +package org.eclipse.cdt.examples.dsf.dataviewer; +//#else +//#package org.eclipse.cdt.examples.dsf.dataviewer.answers; +//#endif + +import java.util.HashSet; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.Set; +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; + +import org.eclipse.cdt.dsf.concurrent.ConfinedToDsfExecutor; +import org.eclipse.cdt.dsf.concurrent.CountingRequestMonitor; +import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor; +import org.eclipse.cdt.dsf.concurrent.DefaultDsfExecutor; +import org.eclipse.cdt.dsf.concurrent.DsfExecutor; +import org.eclipse.cdt.dsf.concurrent.ImmediateExecutor; +import org.eclipse.cdt.dsf.concurrent.Query; +import org.eclipse.cdt.dsf.concurrent.ThreadSafe; +import org.eclipse.cdt.dsf.ui.concurrent.DisplayDsfExecutor; +import org.eclipse.jface.viewers.ILazyContentProvider; +import org.eclipse.jface.viewers.TableViewer; +import org.eclipse.jface.viewers.Viewer; +import org.eclipse.swt.SWT; +import org.eclipse.swt.graphics.Font; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.swt.widgets.Table; + +/** + * Data viewer based on a table, which reads data from multiple data + * providers using asynchronous methods and performs a compultation + * on the retrieved data. + *

+ * This example builds on the {@link AsyncDataViewer} example and + * demonstrates the pitfalls of retrieving data from multiple sources + * asynchronously: The data is retrieved separate from a set of providers + * as well as from a data provider that sums the values from the other + * providers. The viewer then performs a check to ensure consistency of + * retrieved data. If the retrieved data is inconsistent an "INCORRECT" + * label is added in the viewer. + *

+ *

+ * This viewer is updated periodically every 10 seconds, instead of being + * updated with every change in every data provider, which would overwhelm + * the viewer. + *

+ */ +@ConfinedToDsfExecutor("fDisplayExecutor") +public class AsyncSumDataViewer implements ILazyContentProvider +{ + /** View update frequency interval. */ + final private static int UPDATE_INTERVAL = 10000; + + /** Executor to use instead of Display.asyncExec(). **/ + @ThreadSafe + final private DsfExecutor fDisplayExecutor; + + // The viewer and generator that this content provider using. + final private TableViewer fViewer; + final private IDataGenerator[] fDataGenerators; + final private IDataGenerator fSumGenerator; + + // Fields used in request cancellation logic. + private List fItemDataRequestMonitors = + new LinkedList(); + private Set fIndexesToCancel = new HashSet(); + private int fCancelCallsPending = 0; + private Future fRefreshFuture; + + public AsyncSumDataViewer(TableViewer viewer, + IDataGenerator[] generators, IDataGenerator sumGenerator) + { + fViewer = viewer; + fDisplayExecutor = DisplayDsfExecutor.getDisplayDsfExecutor( + fViewer.getTable().getDisplay()); + fDataGenerators = generators; + fSumGenerator = sumGenerator; + + // Schedule a task to refresh the viewer periodically. + fRefreshFuture = fDisplayExecutor.scheduleAtFixedRate( + new Runnable() { + public void run() { + queryItemCount(); + } + }, + UPDATE_INTERVAL, UPDATE_INTERVAL, TimeUnit.MILLISECONDS); + } + + public void dispose() { + // Cancel the periodic task of refreshing the view. + fRefreshFuture.cancel(false); + + // Cancel any outstanding data requests. + for (ValueCountingRequestMonitor rm : fItemDataRequestMonitors) { + rm.cancel(); + } + fItemDataRequestMonitors.clear(); + } + + public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { + // Set the initial count to the viewer after the input is set. + queryItemCount(); + } + + public void updateElement(final int index) { + // Calculate the visible index range. + final int topIdx = fViewer.getTable().getTopIndex(); + final int botIdx = topIdx + getVisibleItemCount(topIdx); + + // Request the item for the given index. + queryValue(index); + + // Invoke a cancel task with a delay. The delay allows multiple cancel + // calls to be combined together improving performance of the viewer. + fCancelCallsPending++; + fDisplayExecutor.execute( + new Runnable() { public void run() { + cancelStaleRequests(topIdx, botIdx); + }}); + } + + /** + * Calculates the number of visible items based on the top item index and + * table bounds. + * @param top Index of top item. + * @return calculated number of items in viewer + */ + private int getVisibleItemCount(int top) { + Table table = fViewer.getTable(); + int itemCount = table.getItemCount(); + return Math.min( + (table.getBounds().height / table.getItemHeight()) + 2, + itemCount - top); + } + + /** + * Retrieve the up to date count. + */ + private void queryItemCount() { + // Note:The count is retrieved from the sum generator only, the sum + // generator is responsible for calculating the count based on + // individual data providers' counts. + fIndexesToCancel.clear(); + fSumGenerator.getCount( + new DataRequestMonitor(fDisplayExecutor, null) { + @Override + protected void handleSuccess() { + setCountToViewer(getData()); + } + @Override + protected void handleRejectedExecutionException() { + // Shutting down, ignore. + } + }); + } + + /** + * Set the givne count to the viewer. This will cause the viewer will + * refresh all items' data as well. + * @param count New count to set to viewer. + */ + private void setCountToViewer(int count) { + if (!fViewer.getTable().isDisposed()) { + fViewer.setItemCount(count); + fViewer.getTable().clearAll(); + } + } + + /** + * Retrieves value of an element at given index. When complete the value + * is written to the viewer. + * @param index Index of value to retrieve. + */ + private void queryValue(final int index) { + // Values retrieved asynchronously from providers are stored in local + // arrays. + final int[] values = new int[fDataGenerators.length]; + final int[] sum = new int[1]; + + // Counting request monitor is invoked when the required number of + // value requests is completed. + final ValueCountingRequestMonitor crm = + new ValueCountingRequestMonitor(index) + { + @Override + protected void handleCompleted() { + fItemDataRequestMonitors.remove(this); + + // Check if the request completed successfully, otherwise + // ignore it. + if (isSuccess()) { + StringBuilder result = new StringBuilder(); + int calcSum = 0; + for (int value : values) { + if (result.length() != 0) result.append(" + "); + result.append(value); + calcSum += value; + } + result.append(" = "); + result.append(sum[0]); + if (calcSum != sum[0]) { + result.append(" !INCORRECT! "); + } + setValueToViewer(fIndex, result.toString()); + } + }; + }; + + // Request data from each data generator. + for (int i = 0; i < fDataGenerators.length; i++) { + final int finalI = i; + fDataGenerators[i].getValue( + index, + // Use the display executor to construct the request monitor, + // this will cause the handleCompleted() method to be + // automatically called on the display thread. + new DataRequestMonitor( + ImmediateExecutor.getInstance(), crm) + { + @Override + protected void handleSuccess() { + values[finalI] = getData(); + crm.done(); + } + }); + } + + // Separately request data from the sum data generator. + fSumGenerator.getValue( + index, + new DataRequestMonitor( + ImmediateExecutor.getInstance(), crm) + { + @Override + protected void handleSuccess() { + sum[0] = getData(); + crm.done(); + } + }); + + crm.setDoneCount(fDataGenerators.length + 1); + fItemDataRequestMonitors.add(crm); + } + + /** + * Write the view value to the viewer. + *

Note: This method must be called in the display thread.

+ * @param index Index of value to set. + * @param value New value. + */ + private void setValueToViewer(int index, String value) { + if (!fViewer.getTable().isDisposed()) { + fViewer.replace(value, index); + } + } + + /** + * Dedicated class for data item requests. This class holds the index + * argument so it can be examined when canceling stale requests. + */ + private class ValueCountingRequestMonitor extends CountingRequestMonitor { + /** Index is used when canceling stale requests. */ + int fIndex; + + ValueCountingRequestMonitor(int index) { + super(fDisplayExecutor, null); + fIndex = index; + } + + @Override + protected void handleRejectedExecutionException() { + // Shutting down, ignore. + } + } + + /** + * Cancels any outstanding value requests for items which are no longer + * visible in the viewer. + * + * @param topIdx Index of top visible item in viewer. + * @param botIdx Index of bottom visible item in viewer. + */ + private void cancelStaleRequests(int topIdx, int botIdx) { + // Decrement the count of outstanding cancel calls. + fCancelCallsPending--; + + // Must check again, in case disposed while re-dispatching. + if (fDataGenerators == null || fViewer.getTable().isDisposed()) return; + + // Go through the outstanding requests and cancel any that + // are not visible anymore. + for (Iterator itr = + fItemDataRequestMonitors.iterator(); itr.hasNext();) + { + ValueCountingRequestMonitor item = itr.next(); + if (item.fIndex < topIdx || item.fIndex > botIdx) { + // Set the item to canceled status, so that the data provider + // will ignore it. + item.cancel(); + + // Add the item index to list of indexes that were canceled, + // which will be sent to the table widget. + fIndexesToCancel.add(item.fIndex); + + // Remove the item from the outstanding cancel requests. + itr.remove(); + } + } + if (!fIndexesToCancel.isEmpty() && fCancelCallsPending == 0) { + Set canceledIdxs = fIndexesToCancel; + fIndexesToCancel = new HashSet(); + + // Clear the indexes of the canceled request, so that the + // viewer knows to request them again when needed. + // Note: clearing using TableViewer.clear(int) seems very + // inefficient, it's better to use Table.clear(int[]). + int[] canceledIdxsArray = new int[canceledIdxs.size()]; + int i = 0; + for (Integer index : canceledIdxs) { + canceledIdxsArray[i++] = index; + } + fViewer.getTable().clear(canceledIdxsArray); + } + } + + /** + * The entry point for the example. + * @param args Program arguments. + */ + public static void main(String[] args) { + // Create the shell to hold the viewer. + Display display = new Display(); + Shell shell = new Shell(display, SWT.SHELL_TRIM); + shell.setLayout(new GridLayout()); + GridData data = new GridData(GridData.FILL_BOTH); + shell.setLayoutData(data); + Font font = new Font(display, "Courier", 10, SWT.NORMAL); + + // Create the table viewer. + TableViewer tableViewer = + new TableViewer(shell, SWT.BORDER | SWT.VIRTUAL); + tableViewer.getControl().setLayoutData(data); + + // Single executor (and single thread) is used by all data generators, + // including the sum generator. + DsfExecutor executor = new DefaultDsfExecutor("Example executor"); + + // Create the data generator. + final IDataGenerator[] generators = new IDataGenerator[5]; + for (int i = 0; i < generators.length; i++) { + generators[i] = new DataGeneratorWithExecutor(executor); + } + final IDataGenerator sumGenerator = + new AsyncSumDataGenerator(executor, generators); + + // Create the content provider which will populate the viewer. + AsyncSumDataViewer contentProvider = + new AsyncSumDataViewer(tableViewer, generators, sumGenerator); + tableViewer.setContentProvider(contentProvider); + tableViewer.setInput(new Object()); + + // Open the shell and service the display dispatch loop until user + // closes the shell. + shell.open(); + while (!shell.isDisposed()) { + if (!display.readAndDispatch()) + display.sleep(); + } + + // The IDataGenerator.shutdown() method is asynchronous, this requires + // using a query again in order to wait for its completion. + Query shutdownQuery = new Query() { + @Override + protected void execute(DataRequestMonitor rm) { + CountingRequestMonitor crm = new CountingRequestMonitor( + ImmediateExecutor.getInstance(), rm); + for (int i = 0; i < generators.length; i++) { + generators[i].shutdown(crm); + } + sumGenerator.shutdown(crm); + crm.setDoneCount(generators.length); + } + }; + + executor.execute(shutdownQuery); + try { + shutdownQuery.get(); + } catch (Exception e) {} + + // Shut down the display. + font.dispose(); + display.dispose(); + } +} diff --git a/dsf/org.eclipse.cdt.examples.dsf/src_preprocess/org/eclipse/cdt/examples/dsf/dataviewer/DataGeneratorCacheManager.java b/dsf/org.eclipse.cdt.examples.dsf/src_preprocess/org/eclipse/cdt/examples/dsf/dataviewer/DataGeneratorCacheManager.java new file mode 100644 index 00000000000..1e1d4e74e89 --- /dev/null +++ b/dsf/org.eclipse.cdt.examples.dsf/src_preprocess/org/eclipse/cdt/examples/dsf/dataviewer/DataGeneratorCacheManager.java @@ -0,0 +1,165 @@ +/******************************************************************************* + * Copyright (c) 2011 Wind River Systems 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 + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +//#ifdef exercises +package org.eclipse.cdt.examples.dsf.dataviewer; +//#else +//#package org.eclipse.cdt.examples.dsf.dataviewer.answers; +//#endif + +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor; +import org.eclipse.cdt.dsf.concurrent.ICache; +import org.eclipse.cdt.dsf.concurrent.ImmediateInDsfExecutor; +import org.eclipse.cdt.dsf.concurrent.RequestCache; +import org.eclipse.cdt.examples.dsf.DsfExamplesPlugin; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; + +/** + * A wrapper class for the {@link IDataGenerator} interface, which returns + * ACPM cache objects to use for data retrieval instead of calling + * {@link IDataGenerator} asynchronous methods directly. + */ +public class DataGeneratorCacheManager implements IDataGenerator.Listener { + + /** Cache class for retrieving the data generator's count. */ + private class CountCache extends RequestCache { + + public CountCache() { + super(fExecutor); + } + + @Override + protected void retrieve(DataRequestMonitor rm) { + fDataGenerator.getCount(rm); + } + + /** + * Reset the cache when the count is changed. + */ + public void countChanged() { + // Make sure that if clients are currently waiting for a count, + // they are notified of the update (their request monitors will be + // completed with an error). They shoudl then re-request data + // from provider again. + setAndReset(null, new Status(IStatus.ERROR, DsfExamplesPlugin.PLUGIN_ID, "Count changed")); + } + } + + /** Cache class for retrieving the data generator's values. */ + private class ValueCache extends RequestCache { + private int fIndex; + + public ValueCache(int index) { + super(fExecutor); + fIndex = index; + } + + @Override + protected void retrieve(org.eclipse.cdt.dsf.concurrent.DataRequestMonitor rm) { + fDataGenerator.getValue(fIndex, rm); + }; + + /** + * @see CountCache#countChanged() + */ + public void valueChanged() { + setAndReset(null, new Status(IStatus.ERROR, DsfExamplesPlugin.PLUGIN_ID, "Value changed")); + } + } + + /** + * Executor used to synchronize data access in this cache manager. + * It has to be the same executor that is used by the data generators in + * order to guarantee data consistency. + */ + private ImmediateInDsfExecutor fExecutor; + + /** + * Data generator that this cache manager is a wrapper for. + */ + private IDataGenerator fDataGenerator; + + /** Cache for data generator's count */ + private CountCache fCountCache; + + /** + * Map of caches for retrieving values. Each value index has a separate + * cache value object. + */ + private Map fValueCaches = new HashMap(); + + public DataGeneratorCacheManager(ImmediateInDsfExecutor executor, IDataGenerator dataGenerator) { + fExecutor = executor; + fDataGenerator = dataGenerator; + fDataGenerator.addListener(this); + } + + public void dispose() { + fDataGenerator.removeListener(this); + } + + /** + * Returns the data generator that this cache manager wraps. + */ + public IDataGenerator getDataGenerator() { + return fDataGenerator; + } + + /** + * Returns the cache for data generator count. + */ + public ICache getCount() { + if (fCountCache == null) { + fCountCache = new CountCache(); + } + return fCountCache; + } + + /** + * Returns the cache for a value at given index. + * + * @param index Index of value to return. + * @return Cache object for given value. + */ + public ICache getValue(int index) { + ValueCache value = fValueCaches.get(index); + if (value == null) { + value = new ValueCache(index); + fValueCaches.put(index, value); + } + + return value; + } + + public void countChanged() { + // Reset the count cache and all the value caches. + if (fCountCache != null) { + fCountCache.countChanged(); + } + for (ValueCache value : fValueCaches.values()) { + value.valueChanged(); + } + } + + public void valuesChanged(Set indexes) { + // Reset selected value caches. + for (Integer index : indexes) { + ValueCache value = fValueCaches.get(index); + if (value != null) { + value.valueChanged(); + } + } + } +} diff --git a/dsf/org.eclipse.cdt.examples.dsf/src_preprocess/org/eclipse/cdt/examples/dsf/dataviewer/DataGeneratorWithExecutor.java b/dsf/org.eclipse.cdt.examples.dsf/src_preprocess/org/eclipse/cdt/examples/dsf/dataviewer/DataGeneratorWithExecutor.java index 3a7393c7fd9..d1ee0b542ed 100644 --- a/dsf/org.eclipse.cdt.examples.dsf/src_preprocess/org/eclipse/cdt/examples/dsf/dataviewer/DataGeneratorWithExecutor.java +++ b/dsf/org.eclipse.cdt.examples.dsf/src_preprocess/org/eclipse/cdt/examples/dsf/dataviewer/DataGeneratorWithExecutor.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2006, 2009 Wind River Systems and others. + * Copyright (c) 2006, 2011 Wind River Systems 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 @@ -14,14 +14,14 @@ package org.eclipse.cdt.examples.dsf.dataviewer; //#package org.eclipse.cdt.examples.dsf.dataviewer.answers; //#endif -import java.util.HashSet; +import java.util.HashMap; //#ifdef answers //#import java.util.Iterator; //#endif import java.util.LinkedList; import java.util.List; import java.util.Random; -import java.util.Set; +import java.util.Map; import java.util.concurrent.RejectedExecutionException; import java.util.concurrent.TimeUnit; @@ -70,6 +70,16 @@ public class DataGeneratorWithExecutor implements IDataGenerator { Request(RequestMonitor rm) { fRequestMonitor = rm; + + rm.addCancelListener(new RequestMonitor.ICanceledListener() { + public void requestCanceled(RequestMonitor rm) { + fExecutor.execute(new DsfRunnable() { + public void run() { + fQueue.remove(Request.this); + } + }); + } + }); } } @@ -93,7 +103,7 @@ public class DataGeneratorWithExecutor implements IDataGenerator { //#endif class ItemRequest extends Request { final int fIndex; - ItemRequest(int index, DataRequestMonitor rm) { + ItemRequest(int index, DataRequestMonitor rm) { super(rm); fIndex = index; } @@ -156,24 +166,20 @@ public class DataGeneratorWithExecutor implements IDataGenerator { //#else //# @ConfinedToDsfExecutor("fExecutor") //#endif - private Set fChangedIndexes = new HashSet(); + private Map fChangedValues = + new HashMap(); - // Flag used to ensure that requests are processed sequentially. - //#ifdef exercises - // TODO Exercise 4 - Add an annotation (ThreadSafe/ConfinedToDsfExecutor) - // indicating allowed thread access to this class/method/member - //#else -//# @ConfinedToDsfExecutor("fExecutor") - //#endif - private boolean fServiceQueueInProgress = false; - - //#ifdef exercises - // TODO Exercise 4 - Add an annotation (ThreadSafe/ConfinedToDsfExecutor) - // indicating allowed thread access to this class/method/member - //#endif public DataGeneratorWithExecutor() { // Create the executor - fExecutor = new DefaultDsfExecutor("Supplier Executor"); + this(new DefaultDsfExecutor("Supplier Executor")); + } + //#ifdef exercises + // TODO Exercise 4 - Add an annotation (ThreadSafe/ConfinedToDsfExecutor) + // indicating allowed thread access to this class/method/member + //#endif + public DataGeneratorWithExecutor(DsfExecutor executor) { + // Create the executor + fExecutor = executor; // Schedule a runnable to make the random changes. fExecutor.scheduleAtFixedRate( @@ -182,8 +188,8 @@ public class DataGeneratorWithExecutor implements IDataGenerator { randomChanges(); } }, - RANDOM_CHANGE_INTERVAL, - RANDOM_CHANGE_INTERVAL, + new Random().nextInt() % RANDOM_CHANGE_INTERVAL, + RANDOM_CHANGE_INTERVAL, //Add a 10% variance to the interval. TimeUnit.MILLISECONDS); } @@ -197,8 +203,9 @@ public class DataGeneratorWithExecutor implements IDataGenerator { public void run() { // Empty the queue of requests and fail them. for (Request request : fQueue) { - request.fRequestMonitor.setStatus( - new Status(IStatus.ERROR, DsfExamplesPlugin.PLUGIN_ID, "Supplier shut down")); + request.fRequestMonitor.setStatus(new Status( + IStatus.ERROR, DsfExamplesPlugin.PLUGIN_ID, + "Supplier shut down")); request.fRequestMonitor.done(); } fQueue.clear(); @@ -209,7 +216,8 @@ public class DataGeneratorWithExecutor implements IDataGenerator { } }); } catch (RejectedExecutionException e) { - rm.setStatus(new Status(IStatus.ERROR, DsfExamplesPlugin.PLUGIN_ID, "Supplier shut down")); + rm.setStatus(new Status(IStatus.ERROR, DsfExamplesPlugin.PLUGIN_ID, + "Supplier shut down")); rm.done(); } } @@ -227,7 +235,9 @@ public class DataGeneratorWithExecutor implements IDataGenerator { } }); } catch (RejectedExecutionException e) { - rm.setStatus(new Status(IStatus.ERROR, DsfExamplesPlugin.PLUGIN_ID, "Supplier shut down")); + rm.setStatus(new Status( + IStatus.ERROR, DsfExamplesPlugin.PLUGIN_ID, + "Supplier shut down")); rm.done(); } } @@ -236,7 +246,7 @@ public class DataGeneratorWithExecutor implements IDataGenerator { // TODO Exercise 4 - Add an annotation (ThreadSafe/ConfinedToDsfExecutor) // indicating allowed thread access to this class/method/member //#endif - public void getValue(final int index, final DataRequestMonitor rm) { + public void getValue(final int index, final DataRequestMonitor rm) { try { fExecutor.execute( new DsfRunnable() { public void run() { @@ -245,7 +255,8 @@ public class DataGeneratorWithExecutor implements IDataGenerator { } }); } catch (RejectedExecutionException e) { - rm.setStatus(new Status(IStatus.ERROR, DsfExamplesPlugin.PLUGIN_ID, "Supplier shut down")); + rm.setStatus(new Status(IStatus.ERROR, DsfExamplesPlugin.PLUGIN_ID, + "Supplier shut down")); rm.done(); } } @@ -286,7 +297,16 @@ public class DataGeneratorWithExecutor implements IDataGenerator { //# @ConfinedToDsfExecutor("fExecutor") //#endif private void serviceQueue() { - + fExecutor.schedule( + new DsfRunnable() { + public void run() { + doServiceQueue(); + } + }, + PROCESSING_DELAY, TimeUnit.MILLISECONDS); + } + + private void doServiceQueue() { //#ifdef exercises // TODO Exercise 3 - Add logic to discard cancelled requests from queue. // Hint: Since serviceQueue() is called using the executor, and the @@ -305,33 +325,16 @@ public class DataGeneratorWithExecutor implements IDataGenerator { //# } //#endif - // If a queue servicing is already scheduled, do nothing. - if (fServiceQueueInProgress) { - return; - } - - if (fQueue.size() != 0) { + while (fQueue.size() != 0) { // If there are requests to service, remove one from the queue and // schedule a runnable to process the request after a processing // delay. - fServiceQueueInProgress = true; - final Request request = fQueue.remove(0); - fExecutor.schedule( - new DsfRunnable() { - public void run() { - if (request instanceof CountRequest) { - processCountRequest((CountRequest)request); - } else if (request instanceof ItemRequest) { - processItemRequest((ItemRequest)request); - } - - // Reset the processing flag and process next - // request. - fServiceQueueInProgress = false; - serviceQueue(); - } - }, - PROCESSING_DELAY, TimeUnit.MILLISECONDS); + Request request = fQueue.remove(0); + if (request instanceof CountRequest) { + processCountRequest((CountRequest)request); + } else if (request instanceof ItemRequest) { + processItemRequest((ItemRequest)request); + } } } @@ -343,7 +346,8 @@ public class DataGeneratorWithExecutor implements IDataGenerator { //#endif private void processCountRequest(CountRequest request) { @SuppressWarnings("unchecked") // Suppress warning about lost type info. - DataRequestMonitor rm = (DataRequestMonitor)request.fRequestMonitor; + DataRequestMonitor rm = + (DataRequestMonitor)request.fRequestMonitor; rm.setData(fCount); rm.done(); @@ -357,12 +361,13 @@ public class DataGeneratorWithExecutor implements IDataGenerator { //#endif private void processItemRequest(ItemRequest request) { @SuppressWarnings("unchecked") // Suppress warning about lost type info. - DataRequestMonitor rm = (DataRequestMonitor)request.fRequestMonitor; + DataRequestMonitor rm = + (DataRequestMonitor)request.fRequestMonitor; - if (fChangedIndexes.contains(request.fIndex)) { - rm.setData("Changed: " + request.fIndex); + if (fChangedValues.containsKey(request.fIndex)) { + rm.setData(fChangedValues.get(request.fIndex)); } else { - rm.setData(Integer.toString(request.fIndex)); + rm.setData(request.fIndex); } rm.done(); } @@ -398,10 +403,11 @@ public class DataGeneratorWithExecutor implements IDataGenerator { private void randomCountReset() { // Calculate the new count. Random random = new java.util.Random(); - fCount = MIN_COUNT + Math.abs(random.nextInt()) % (MAX_COUNT - MIN_COUNT); + fCount = MIN_COUNT + + Math.abs(random.nextInt()) % (MAX_COUNT - MIN_COUNT); // Reset the changed values. - fChangedIndexes.clear(); + fChangedValues.clear(); // Notify listeners for (Listener listener : fListeners) { @@ -421,17 +427,19 @@ public class DataGeneratorWithExecutor implements IDataGenerator { private void randomDataChange() { // Calculate the indexes to change. Random random = new java.util.Random(); - Set set = new HashSet(); + Map changed = new HashMap(); for (int i = 0; i < fCount * RANDOM_CHANGE_SET_PERCENTAGE / 100; i++) { - set.add( new Integer(Math.abs(random.nextInt()) % fCount) ); - } + int randomIndex = Math.abs(random.nextInt()) % fCount; + int randomValue = Math.abs(random.nextInt()) % fCount; + changed.put(randomIndex, randomValue); + } // Add the indexes to an overall set of changed indexes. - fChangedIndexes.addAll(set); + fChangedValues.putAll(changed); // Notify listeners - for (Listener listener : fListeners) { - listener.valuesChanged(set); + for (Object listener : fListeners) { + ((Listener)listener).valuesChanged(changed.keySet()); } } } diff --git a/dsf/org.eclipse.cdt.examples.dsf/src_preprocess/org/eclipse/cdt/examples/dsf/dataviewer/DataGeneratorWithThread.java b/dsf/org.eclipse.cdt.examples.dsf/src_preprocess/org/eclipse/cdt/examples/dsf/dataviewer/DataGeneratorWithThread.java index e4e736a14ea..3b4a909e884 100644 --- a/dsf/org.eclipse.cdt.examples.dsf/src_preprocess/org/eclipse/cdt/examples/dsf/dataviewer/DataGeneratorWithThread.java +++ b/dsf/org.eclipse.cdt.examples.dsf/src_preprocess/org/eclipse/cdt/examples/dsf/dataviewer/DataGeneratorWithThread.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2006, 2009 Wind River Systems and others. + * Copyright (c) 2006, 2011 Wind River Systems 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 @@ -15,9 +15,9 @@ package org.eclipse.cdt.examples.dsf.dataviewer; //#endif import java.util.Collections; -import java.util.HashSet; +import java.util.HashMap; import java.util.Random; -import java.util.Set; +import java.util.Map; import java.util.concurrent.BlockingQueue; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.TimeUnit; @@ -41,7 +41,9 @@ import org.eclipse.cdt.examples.dsf.DsfExamplesPlugin; * synchronization. *

*/ -public class DataGeneratorWithThread extends Thread implements IDataGenerator { +public class DataGeneratorWithThread extends Thread + implements IDataGenerator +{ // Request objects are used to serialize the interface calls into objects // which can then be pushed into a queue. @@ -61,7 +63,7 @@ public class DataGeneratorWithThread extends Thread implements IDataGenerator { class ItemRequest extends Request { final int fIndex; - ItemRequest(int index, DataRequestMonitor rm) { + ItemRequest(int index, DataRequestMonitor rm) { super(rm); fIndex = index; } @@ -76,7 +78,8 @@ public class DataGeneratorWithThread extends Thread implements IDataGenerator { // Main request queue of the data generator. The getValue(), getCount(), // and shutdown() methods write into the queue, while the run() method // reads from it. - private final BlockingQueue fQueue = new LinkedBlockingQueue(); + private final BlockingQueue fQueue = + new LinkedBlockingQueue(); // ListenerList class provides thread safety. private ListenerList fListeners = new ListenerList(); @@ -88,7 +91,8 @@ public class DataGeneratorWithThread extends Thread implements IDataGenerator { private int fCountResetTrigger = 0; // Elements which were modified since the last reset. - private Set fChangedIndexes = Collections.synchronizedSet(new HashSet()); + private Map fChangedValues = + Collections.synchronizedMap(new HashMap()); // Used to determine when to make changes in data. private long fLastChangeTime = System.currentTimeMillis(); @@ -108,7 +112,8 @@ public class DataGeneratorWithThread extends Thread implements IDataGenerator { fQueue.add(new ShutdownRequest(rm)); } else { // - rm.setStatus(new Status(IStatus.ERROR, DsfExamplesPlugin.PLUGIN_ID, "Supplier shut down")); + rm.setStatus(new Status(IStatus.ERROR, DsfExamplesPlugin.PLUGIN_ID, + "Supplier shut down")); rm.done(); } } @@ -117,16 +122,18 @@ public class DataGeneratorWithThread extends Thread implements IDataGenerator { if (!fShutdown.get()) { fQueue.add(new CountRequest(rm)); } else { - rm.setStatus(new Status(IStatus.ERROR, DsfExamplesPlugin.PLUGIN_ID, "Supplier shut down")); + rm.setStatus(new Status(IStatus.ERROR, DsfExamplesPlugin.PLUGIN_ID, + "Supplier shut down")); rm.done(); } } - public void getValue(int index, DataRequestMonitor rm) { + public void getValue(int index, DataRequestMonitor rm) { if (!fShutdown.get()) { fQueue.add(new ItemRequest(index, rm)); } else { - rm.setStatus(new Status(IStatus.ERROR, DsfExamplesPlugin.PLUGIN_ID, "Supplier shut down")); + rm.setStatus(new Status(IStatus.ERROR, DsfExamplesPlugin.PLUGIN_ID, + "Supplier shut down")); rm.done(); } } @@ -150,7 +157,6 @@ public class DataGeneratorWithThread extends Thread implements IDataGenerator { // If a request was dequeued, process it. if (request != null) { // Simulate a processing delay. - Thread.sleep(PROCESSING_DELAY); if (request instanceof CountRequest) { processCountRequest((CountRequest)request); @@ -162,6 +168,8 @@ public class DataGeneratorWithThread extends Thread implements IDataGenerator { request.fRequestMonitor.done(); break; } + } else { + Thread.sleep(PROCESSING_DELAY); } // Simulate data changes. @@ -173,7 +181,8 @@ public class DataGeneratorWithThread extends Thread implements IDataGenerator { private void processCountRequest(CountRequest request) { @SuppressWarnings("unchecked") // Suppress warning about lost type info. - DataRequestMonitor rm = (DataRequestMonitor)request.fRequestMonitor; + DataRequestMonitor rm = + (DataRequestMonitor)request.fRequestMonitor; rm.setData(fCount); rm.done(); @@ -181,12 +190,13 @@ public class DataGeneratorWithThread extends Thread implements IDataGenerator { private void processItemRequest(ItemRequest request) { @SuppressWarnings("unchecked") // Suppress warning about lost type info. - DataRequestMonitor rm = (DataRequestMonitor)request.fRequestMonitor; + DataRequestMonitor rm = + (DataRequestMonitor)request.fRequestMonitor; - if (fChangedIndexes.contains(request.fIndex)) { - rm.setData("Changed: " + request.fIndex); + if (fChangedValues.containsKey(request.fIndex)) { + rm.setData(fChangedValues.get(request.fIndex)); } else { - rm.setData(Integer.toString(request.fIndex)); + rm.setData(request.fIndex); } rm.done(); } @@ -194,12 +204,14 @@ public class DataGeneratorWithThread extends Thread implements IDataGenerator { private void randomChanges() { // Check if enough time is elapsed. - if (System.currentTimeMillis() > fLastChangeTime + RANDOM_CHANGE_INTERVAL) { + if (System.currentTimeMillis() > + fLastChangeTime + RANDOM_CHANGE_INTERVAL) + { fLastChangeTime = System.currentTimeMillis(); // Once every number of changes, reset the count, the rest of the // times just change certain values. - if (++fCountResetTrigger % RANDOM_COUNT_CHANGE_INTERVALS == 0){ + if (++fCountResetTrigger % RANDOM_COUNT_CHANGE_INTERVALS == 0) { randomCountReset(); } else { randomDataChange(); @@ -213,7 +225,7 @@ public class DataGeneratorWithThread extends Thread implements IDataGenerator { fCount = MIN_COUNT + Math.abs(random.nextInt()) % (MAX_COUNT - MIN_COUNT); // Reset the changed values. - fChangedIndexes.clear(); + fChangedValues.clear(); // Notify listeners for (Object listener : fListeners.getListeners()) { @@ -224,17 +236,19 @@ public class DataGeneratorWithThread extends Thread implements IDataGenerator { private void randomDataChange() { // Calculate the indexes to change. Random random = new java.util.Random(); - Set set = new HashSet(); + Map changed = new HashMap(); for (int i = 0; i < fCount * RANDOM_CHANGE_SET_PERCENTAGE / 100; i++) { - set.add( new Integer(Math.abs(random.nextInt()) % fCount) ); + int randomIndex = Math.abs(random.nextInt()) % fCount; + int randomValue = Math.abs(random.nextInt()) % fCount; + changed.put(randomIndex, randomValue); } // Add the indexes to an overall set of changed indexes. - fChangedIndexes.addAll(set); + fChangedValues.putAll(changed); // Notify listeners for (Object listener : fListeners.getListeners()) { - ((Listener)listener).valuesChanged(set); + ((Listener)listener).valuesChanged(changed.keySet()); } } } diff --git a/dsf/org.eclipse.cdt.examples.dsf/src_preprocess/org/eclipse/cdt/examples/dsf/dataviewer/IDataGenerator.java b/dsf/org.eclipse.cdt.examples.dsf/src_preprocess/org/eclipse/cdt/examples/dsf/dataviewer/IDataGenerator.java index 398b09a4e88..ef7eb53f27a 100644 --- a/dsf/org.eclipse.cdt.examples.dsf/src_preprocess/org/eclipse/cdt/examples/dsf/dataviewer/IDataGenerator.java +++ b/dsf/org.eclipse.cdt.examples.dsf/src_preprocess/org/eclipse/cdt/examples/dsf/dataviewer/IDataGenerator.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2006, 2009 Wind River Systems and others. + * Copyright (c) 2006, 2011 Wind River Systems 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 @@ -41,11 +41,11 @@ public interface IDataGenerator { // Changing the count range can stress the scalability of the system, while // changing of the process delay and random change interval can stress // its performance. - final static int MIN_COUNT = 100; - final static int MAX_COUNT = 200; - final static int PROCESSING_DELAY = 10; - final static int RANDOM_CHANGE_INTERVAL = 10000; - final static int RANDOM_COUNT_CHANGE_INTERVALS = 3; + final static int MIN_COUNT = 50; + final static int MAX_COUNT = 100; + final static int PROCESSING_DELAY = 500; + final static int RANDOM_CHANGE_INTERVAL = 4000; + final static int RANDOM_COUNT_CHANGE_INTERVALS = 5; final static int RANDOM_CHANGE_SET_PERCENTAGE = 10; @@ -58,7 +58,7 @@ public interface IDataGenerator { // Data access methods. void getCount(DataRequestMonitor rm); - void getValue(int index, DataRequestMonitor rm); + void getValue(int index, DataRequestMonitor rm); // Method used to shutdown the data generator including any threads that // it may use. diff --git a/dsf/org.eclipse.cdt.examples.dsf/src_preprocess/org/eclipse/cdt/examples/dsf/dataviewer/SyncDataViewer.java b/dsf/org.eclipse.cdt.examples.dsf/src_preprocess/org/eclipse/cdt/examples/dsf/dataviewer/SyncDataViewer.java index 6ce9c06ef4e..335d198415f 100644 --- a/dsf/org.eclipse.cdt.examples.dsf/src_preprocess/org/eclipse/cdt/examples/dsf/dataviewer/SyncDataViewer.java +++ b/dsf/org.eclipse.cdt.examples.dsf/src_preprocess/org/eclipse/cdt/examples/dsf/dataviewer/SyncDataViewer.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2008, 2009 Wind River Systems and others. + * Copyright (c) 2008, 2011 Wind River Systems 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 @@ -14,8 +14,11 @@ package org.eclipse.cdt.examples.dsf.dataviewer; //#package org.eclipse.cdt.examples.dsf.dataviewer.answers; //#endif +import java.util.Arrays; +import java.util.List; import java.util.Set; +import org.eclipse.cdt.dsf.concurrent.CountingRequestMonitor; import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor; import org.eclipse.cdt.dsf.concurrent.ImmediateExecutor; import org.eclipse.cdt.dsf.concurrent.Query; @@ -35,8 +38,8 @@ import org.eclipse.swt.widgets.Shell; * This viewer implements the {@link IStructuredContentProvider} interface * which is used by the JFace TableViewer class to populate a Table. This * interface contains one principal methods for reading data {@link #getElements(Object)}, - * which synchronously returns an array of elements. In order to implement this - * method using the asynchronous data generator, this provider uses the + * which synchronously returns an array of elements. In order to implement + * this method using the asynchronous data generator, this provider uses the * {@link Query} object. *

*/ @@ -84,27 +87,43 @@ public class SyncDataViewer return new Object[0]; } - // Create the array that will be filled with elements. - // For each index in the array execute a query to get the element at - // that index. - final Object[] elements = new Object[count]; - - for (int i = 0; i < count; i++) { - final int index = i; - Query valueQuery = new Query() { - @Override - protected void execute(DataRequestMonitor rm) { - fDataGenerator.getValue(index, rm); + final int finalCount = count; + Query> valueQuery = new Query>() { + @Override + protected void execute(final DataRequestMonitor> rm) { + final Integer[] retVal = new Integer[finalCount]; + final CountingRequestMonitor crm = new CountingRequestMonitor( + ImmediateExecutor.getInstance(), rm) + { + @Override + protected void handleSuccess() { + rm.setData(Arrays.asList(retVal)); + rm.done(); + }; + }; + for (int i = 0; i < finalCount; i++) { + final int finalI = i; + fDataGenerator.getValue( + i, + new DataRequestMonitor( + ImmediateExecutor.getInstance(), crm) + { + @Override + protected void handleSuccess() { + retVal[finalI] = getData(); + crm.done(); + } + }); } - }; - ImmediateExecutor.getInstance().execute(valueQuery); - try { - elements[i] = valueQuery.get(); - } catch (Exception e) { - elements[i] = "error"; - } + crm.setDoneCount(finalCount); + } + }; + ImmediateExecutor.getInstance().execute(valueQuery); + try { + return valueQuery.get().toArray(new Integer[0]); + } catch (Exception e) { } - return elements; + return new Object[0]; } public void dispose() { @@ -140,6 +159,10 @@ public class SyncDataViewer }); } + /** + * The entry point for the example. + * @param args Program arguments. + */ public static void main(String[] args) { // Create the shell to hold the viewer. Display display = new Display(); @@ -162,7 +185,8 @@ public class SyncDataViewer //#endif // Create the content provider which will populate the viewer. - SyncDataViewer contentProvider = new SyncDataViewer(tableViewer, generator); + SyncDataViewer contentProvider = + new SyncDataViewer(tableViewer, generator); tableViewer.setContentProvider(contentProvider); tableViewer.setInput(new Object());